Added function mc_build_filename() for processing URL-paths as well
[midnight-commander.git] / src / editor / editcmd.c
blobd35fd07a800f971f917ab51641d21ed4859d8819
1 /* editor high level editing commands
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1996, 1997 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
25 /** \file
26 * \brief Source: editor high level editing commands
27 * \author Paul Sheer
28 * \date 1996, 1997
31 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
33 #include <config.h>
35 #include <assert.h>
36 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <stdlib.h>
46 #include <fcntl.h>
48 #include "lib/global.h"
49 #include "lib/tty/tty.h"
50 #include "lib/tty/key.h" /* XCTRL */
51 #include "lib/mcconfig.h"
52 #include "lib/skin.h"
53 #include "lib/strutil.h" /* utf string functions */
54 #include "lib/lock.h"
55 #include "lib/util.h" /* tilde_expand() */
56 #include "lib/vfs/vfs.h"
57 #include "lib/widget.h"
58 #include "lib/charsets.h"
59 #include "lib/event.h" /* mc_event_raise() */
61 #include "src/history.h"
62 #include "src/setup.h" /* option_tab_spacing */
63 #include "src/selcodepage.h"
64 #include "src/keybind-defaults.h"
65 #include "src/util.h" /* check_for_default() */
66 #include "src/filemanager/layout.h" /* mc_refresh() */
69 #include "edit-impl.h"
70 #include "edit-widget.h"
71 #include "editcmd_dialogs.h"
72 #include "etags.h"
74 /*** global variables ****************************************************************************/
76 /* search and replace: */
77 int search_create_bookmark = FALSE;
79 /* queries on a save */
80 int edit_confirm_save = 1;
82 static int edit_save_cmd (WEdit * edit);
83 static unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l);
85 /*** file scope macro definitions ****************************************************************/
87 #define space_width 1
89 #define TEMP_BUF_LEN 1024
91 #define INPUT_INDEX 9
93 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
94 (and the above) routines to work properly - paul */
96 #define is_digit(x) ((x) >= '0' && (x) <= '9')
98 #define MAIL_DLG_HEIGHT 12
100 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
102 /*** file scope type declarations ****************************************************************/
104 /*** file scope variables ************************************************************************/
106 /*** file scope functions ************************************************************************/
107 /* --------------------------------------------------------------------------------------------- */
109 /* If 0 (quick save) then a) create/truncate <filename> file,
110 b) save to <filename>;
111 if 1 (safe save) then a) save to <tempnam>,
112 b) rename <tempnam> to <filename>;
113 if 2 (do backups) then a) save to <tempnam>,
114 b) rename <filename> to <filename.backup_ext>,
115 c) rename <tempnam> to <filename>. */
117 /* returns 0 on error, -1 on abort */
119 static int
120 edit_save_file (WEdit * edit, const char *filename)
122 char *p;
123 gchar *tmp;
124 long filelen = 0;
125 char *savename = 0;
126 gchar *real_filename;
127 int this_save_mode, fd = -1;
129 if (!filename)
130 return 0;
131 if (!*filename)
132 return 0;
134 if (*filename != PATH_SEP && edit->dir)
136 real_filename = concat_dir_and_file (edit->dir, filename);
138 else
140 real_filename = g_strdup (filename);
143 this_save_mode = option_save_mode;
144 if (this_save_mode != EDIT_QUICK_SAVE)
146 vfs_path_t *vpath = vfs_path_from_str (real_filename);
147 if (!vfs_file_is_local (vpath) || (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1)
150 * The file does not exists yet, so no safe save or
151 * backup are necessary.
153 this_save_mode = EDIT_QUICK_SAVE;
155 vfs_path_free (vpath);
156 if (fd != -1)
157 mc_close (fd);
160 if (this_save_mode == EDIT_QUICK_SAVE && !edit->skip_detach_prompt)
162 int rv;
163 struct stat sb;
165 rv = mc_stat (real_filename, &sb);
166 if (rv == 0 && sb.st_nlink > 1)
168 rv = edit_query_dialog3 (_("Warning"),
169 _("File has hard-links. Detach before saving?"),
170 _("&Yes"), _("&No"), _("&Cancel"));
171 switch (rv)
173 case 0:
174 this_save_mode = EDIT_SAFE_SAVE;
175 /* fallthrough */
176 case 1:
177 edit->skip_detach_prompt = 1;
178 break;
179 default:
180 g_free (real_filename);
181 return -1;
185 /* Prevent overwriting changes from other editor sessions. */
186 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime)
189 /* The default action is "Cancel". */
190 query_set_sel (1);
192 rv = edit_query_dialog2 (_("Warning"),
193 _("The file has been modified in the meantime. Save anyway?"),
194 _("&Yes"), _("&Cancel"));
195 if (rv != 0)
197 g_free (real_filename);
198 return -1;
203 if (this_save_mode != EDIT_QUICK_SAVE)
205 char *savedir, *saveprefix;
206 const char *slashpos;
207 slashpos = strrchr (real_filename, PATH_SEP);
208 if (slashpos)
210 savedir = g_strdup (real_filename);
211 savedir[slashpos - real_filename + 1] = '\0';
213 else
214 savedir = g_strdup (".");
215 saveprefix = concat_dir_and_file (savedir, "cooledit");
216 g_free (savedir);
217 fd = mc_mkstemps (&savename, saveprefix, NULL);
218 g_free (saveprefix);
219 if (!savename)
221 g_free (real_filename);
222 return 0;
224 /* FIXME:
225 * Close for now because mc_mkstemps use pure open system call
226 * to create temporary file and it needs to be reopened by
227 * VFS-aware mc_open().
229 close (fd);
231 else
232 savename = g_strdup (real_filename);
234 int ret;
235 ret = mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
236 ret = mc_chmod (savename, edit->stat1.st_mode);
239 fd = mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode);
240 if (fd == -1)
241 goto error_save;
243 /* pipe save */
244 p = edit_get_write_filter (savename, real_filename);
245 if (p != NULL)
247 FILE *file;
249 mc_close (fd);
250 file = (FILE *) popen (p, "w");
252 if (file)
254 filelen = edit_write_stream (edit, file);
255 #if 1
256 pclose (file);
257 #else
258 if (pclose (file) != 0)
260 tmp = g_strdup_printf (_("Error writing to pipe: %s"), p);
261 edit_error_dialog (_("Error"), tmp);
262 g_free (tmp);
263 g_free (p);
264 goto error_save;
266 #endif
268 else
270 tmp = g_strdup_printf (_("Cannot open pipe for writing: %s"), p);
271 edit_error_dialog (_("Error"), get_sys_error (tmp));
272 g_free (p);
273 g_free (tmp);
274 goto error_save;
276 g_free (p);
278 else if (edit->lb == LB_ASIS)
279 { /* do not change line breaks */
280 long buf;
281 buf = 0;
282 filelen = edit->last_byte;
283 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1)
285 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE)
287 mc_close (fd);
288 goto error_save;
290 buf++;
292 if (mc_write
293 (fd, (char *) edit->buffers1[buf],
294 edit->curs1 & M_EDIT_BUF_SIZE) != (edit->curs1 & M_EDIT_BUF_SIZE))
296 filelen = -1;
298 else if (edit->curs2)
300 edit->curs2--;
301 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
302 if (mc_write
303 (fd,
304 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
305 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
306 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) != 1 + (edit->curs2 & M_EDIT_BUF_SIZE))
308 filelen = -1;
310 else
312 while (--buf >= 0)
314 if (mc_write (fd, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE)
316 filelen = -1;
317 break;
321 edit->curs2++;
323 if (mc_close (fd))
324 goto error_save;
326 /* Update the file information, especially the mtime. */
327 if (mc_stat (savename, &edit->stat1) == -1)
328 goto error_save;
330 else
331 { /* change line breaks */
332 FILE *file;
334 mc_close (fd);
336 file = (FILE *) fopen (savename, "w");
338 if (file)
340 filelen = edit_write_stream (edit, file);
341 fclose (file);
343 else
345 char *msg;
347 msg = g_strdup_printf (_("Cannot open file for writing: %s"), savename);
348 edit_error_dialog (_("Error"), msg);
349 g_free (msg);
350 goto error_save;
354 if (filelen != edit->last_byte)
355 goto error_save;
357 if (this_save_mode == EDIT_DO_BACKUP)
359 assert (option_backup_ext != NULL);
360 tmp = g_strconcat (real_filename, option_backup_ext, (char *) NULL);
361 if (mc_rename (real_filename, tmp) == -1)
363 g_free (tmp);
364 goto error_save;
368 if (this_save_mode != EDIT_QUICK_SAVE)
369 if (mc_rename (savename, real_filename) == -1)
370 goto error_save;
371 g_free (savename);
372 g_free (real_filename);
373 return 1;
374 error_save:
375 /* FIXME: Is this safe ?
376 * if (this_save_mode != EDIT_QUICK_SAVE)
377 * mc_unlink (savename);
379 g_free (real_filename);
380 g_free (savename);
381 return 0;
384 /* --------------------------------------------------------------------------------------------- */
386 static gboolean
387 edit_check_newline (WEdit * edit)
389 return !(option_check_nl_at_eof && edit->last_byte > 0
390 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
391 && edit_query_dialog2 (_("Warning"),
392 _("The file you are saving is not finished with a newline"),
393 _("C&ontinue"), _("&Cancel")));
396 /* --------------------------------------------------------------------------------------------- */
398 static char *
399 edit_get_save_file_as (WEdit * edit)
401 #define DLG_WIDTH 64
402 #define DLG_HEIGHT 14
404 static LineBreaks cur_lb = LB_ASIS;
406 char *filename = edit->filename;
408 const char *lb_names[LB_NAMES] = {
409 N_("&Do not change"),
410 N_("&Unix format (LF)"),
411 N_("&Windows/DOS format (CR LF)"),
412 N_("&Macintosh format (CR)")
415 QuickWidget quick_widgets[] = {
416 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
417 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
418 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
419 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
420 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0,
421 "save-as", &filename),
422 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_("Enter file name:")),
423 QUICK_END
426 QuickDialog Quick_options = {
427 DLG_WIDTH, DLG_HEIGHT, -1, -1,
428 N_("Save As"), "[Save File As]",
429 quick_widgets, NULL, FALSE
432 if (quick_dialog (&Quick_options) != B_CANCEL)
434 char *fname;
436 edit->lb = cur_lb;
437 fname = tilde_expand (filename);
438 g_free (filename);
439 return fname;
442 return NULL;
444 #undef DLG_WIDTH
445 #undef DLG_HEIGHT
448 /** returns 1 on success */
450 static int
451 edit_save_cmd (WEdit * edit)
453 int res, save_lock = 0;
455 if (!edit->locked && !edit->delete_file)
456 save_lock = edit_lock_file (edit);
457 res = edit_save_file (edit, edit->filename);
459 /* Maintain modify (not save) lock on failure */
460 if ((res > 0 && edit->locked) || save_lock)
461 edit->locked = edit_unlock_file (edit);
463 /* On failure try 'save as', it does locking on its own */
464 if (!res)
465 return edit_save_as_cmd (edit);
466 edit->force |= REDRAW_COMPLETELY;
467 if (res > 0)
469 edit->delete_file = 0;
470 edit->modified = 0;
473 return 1;
476 /* --------------------------------------------------------------------------------------------- */
477 /** returns 1 on error */
479 static int
480 edit_load_file_from_filename (WEdit * edit, char *exp)
482 int prev_locked = edit->locked;
483 char *prev_filename = g_strdup (edit->filename);
485 if (!edit_reload (edit, exp))
487 g_free (prev_filename);
488 return 1;
491 if (prev_locked)
493 char *fullpath;
495 fullpath = mc_build_filename (edit->dir, prev_filename, (char *) NULL);
496 unlock_file (fullpath);
497 g_free (fullpath);
499 g_free (prev_filename);
500 return 0;
503 /* --------------------------------------------------------------------------------------------- */
505 static void
506 edit_load_syntax_file (WEdit * edit)
508 char *extdir;
509 int dir = 0;
511 if (geteuid () == 0)
513 dir = query_dialog (_("Syntax file edit"),
514 _("Which syntax file you want to edit?"), D_NORMAL, 2,
515 _("&User"), _("&System Wide"));
518 extdir = g_build_filename (mc_global.sysconfig_dir, "syntax", "Syntax", (char *) NULL);
519 if (!exist_file (extdir))
521 g_free (extdir);
522 extdir = g_build_filename (mc_global.share_data_dir, "syntax", "Syntax", (char *) NULL);
525 if (dir == 0)
527 char *buffer;
529 buffer = concat_dir_and_file (mc_config_get_data_path (), EDIT_SYNTAX_FILE);
530 check_for_default (extdir, buffer);
531 edit_load_file_from_filename (edit, buffer);
532 g_free (buffer);
534 else if (dir == 1)
535 edit_load_file_from_filename (edit, extdir);
537 g_free (extdir);
540 /* --------------------------------------------------------------------------------------------- */
542 static void
543 edit_load_menu_file (WEdit * edit)
545 char *buffer;
546 char *menufile;
547 int dir = 0;
549 dir = query_dialog (_("Menu edit"),
550 _("Which menu file do you want to edit?"), D_NORMAL,
551 geteuid () != 0 ? 2 : 3, _("&Local"), _("&User"), _("&System Wide"));
553 menufile = concat_dir_and_file (mc_global.sysconfig_dir, EDIT_GLOBAL_MENU);
555 if (!exist_file (menufile))
557 g_free (menufile);
558 menufile = concat_dir_and_file (mc_global.share_data_dir, EDIT_GLOBAL_MENU);
561 switch (dir)
563 case 0:
564 buffer = g_strdup (EDIT_LOCAL_MENU);
565 check_for_default (menufile, buffer);
566 chmod (buffer, 0600);
567 break;
569 case 1:
570 buffer = concat_dir_and_file (mc_config_get_data_path (), EDIT_HOME_MENU);
571 check_for_default (menufile, buffer);
572 break;
574 case 2:
575 buffer = concat_dir_and_file (mc_global.sysconfig_dir, EDIT_GLOBAL_MENU);
576 if (!exist_file (buffer))
578 g_free (buffer);
579 buffer = concat_dir_and_file (mc_global.share_data_dir, EDIT_GLOBAL_MENU);
581 break;
583 default:
584 g_free (menufile);
585 return;
588 edit_load_file_from_filename (edit, buffer);
590 g_free (buffer);
591 g_free (menufile);
594 /* --------------------------------------------------------------------------------------------- */
596 static void
597 edit_delete_column_of_text (WEdit * edit)
599 long p, q, r, m1, m2;
600 long b, c, d, n;
602 eval_marks (edit, &m1, &m2);
603 n = edit_move_forward (edit, m1, 0, m2) + 1;
604 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
605 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
606 b = max (min (c, d), min (edit->column1, edit->column2));
607 c = max (c, max (edit->column1, edit->column2));
609 while (n--)
611 r = edit_bol (edit, edit->curs1);
612 p = edit_move_forward3 (edit, r, b, 0);
613 q = edit_move_forward3 (edit, r, c, 0);
614 if (p < m1)
615 p = m1;
616 if (q > m2)
617 q = m2;
618 edit_cursor_move (edit, p - edit->curs1);
619 while (q > p)
621 /* delete line between margins */
622 if (edit_get_byte (edit, edit->curs1) != '\n')
623 edit_delete (edit, 1);
624 q--;
626 if (n)
627 /* move to next line except on the last delete */
628 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
632 /* --------------------------------------------------------------------------------------------- */
633 /** if success return 0 */
635 static int
636 edit_block_delete (WEdit * edit)
638 long count;
639 long start_mark, end_mark;
640 int curs_pos, line_width;
641 long curs_line, c1, c2;
643 if (eval_marks (edit, &start_mark, &end_mark))
644 return 0;
645 if (edit->column_highlight && edit->mark2 < 0)
646 edit_mark_cmd (edit, 0);
647 if ((end_mark - start_mark) > option_max_undo / 2)
649 /* Warning message with a query to continue or cancel the operation */
650 if (edit_query_dialog2
651 (_("Warning"),
653 ("Block is large, you may not be able to undo this action"),
654 _("C&ontinue"), _("&Cancel")))
656 return 1;
659 c1 = min (edit->column1, edit->column2);
660 c2 = max (edit->column1, edit->column2);
661 edit->column1 = c1;
662 edit->column2 = c2;
664 edit_push_markers (edit);
666 curs_line = edit->curs_line;
668 /* calculate line width and cursor position before cut */
669 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
670 edit_eol (edit, edit->curs1));
671 curs_pos = edit->curs_col + edit->over_col;
673 /* move cursor to start of selection */
674 edit_cursor_move (edit, start_mark - edit->curs1);
675 edit_scroll_screen_over_cursor (edit);
676 count = start_mark;
677 if (start_mark < end_mark)
679 if (edit->column_highlight)
681 if (edit->mark2 < 0)
682 edit_mark_cmd (edit, 0);
683 edit_delete_column_of_text (edit);
684 /* move cursor to the saved position */
685 edit_move_to_line (edit, curs_line);
686 /* calculate line width after cut */
687 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
688 edit_eol (edit, edit->curs1));
689 if (option_cursor_beyond_eol && curs_pos > line_width)
690 edit->over_col = curs_pos - line_width;
692 else
694 while (count < end_mark)
696 edit_delete (edit, 1);
697 count++;
701 edit_set_markers (edit, 0, 0, 0, 0);
702 edit->force |= REDRAW_PAGE;
703 return 0;
706 /* --------------------------------------------------------------------------------------------- */
708 static gboolean
709 editcmd_find (WEdit * edit, gsize * len)
711 off_t search_start = edit->search_start;
712 off_t search_end;
713 long start_mark = 0;
714 long end_mark = edit->last_byte;
715 int mark_res = 0;
717 if (edit_search_options.only_in_selection)
719 mark_res = eval_marks (edit, &start_mark, &end_mark);
720 if (mark_res != 0)
722 edit->search->error = MC_SEARCH_E_NOTFOUND;
723 edit->search->error_str = g_strdup (_("Search string not found"));
724 return FALSE;
726 if (edit_search_options.backwards)
728 if (search_start > end_mark || search_start <= start_mark)
730 search_start = end_mark;
733 else
735 if (search_start < start_mark || search_start >= end_mark)
737 search_start = start_mark;
741 else
743 if (edit_search_options.backwards)
744 end_mark = max (1, edit->curs1) - 1;
746 if (edit_search_options.backwards)
748 search_end = end_mark;
749 while ((int) search_start >= start_mark)
751 if (search_end > (off_t) (search_start + edit->search->original_len) &&
752 mc_search_is_fixed_search_str (edit->search))
754 search_end = search_start + edit->search->original_len;
756 if (mc_search_run (edit->search, (void *) edit, search_start, search_end, len)
757 && edit->search->normal_offset == search_start)
759 return TRUE;
761 search_start--;
763 edit->search->error_str = g_strdup (_("Search string not found"));
765 else
767 return mc_search_run (edit->search, (void *) edit, search_start, end_mark, len);
769 return FALSE;
772 /* --------------------------------------------------------------------------------------------- */
774 static char *
775 edit_replace_cmd__conv_to_display (char *str)
777 #ifdef HAVE_CHARSET
778 GString *tmp;
780 tmp = str_convert_to_display (str);
781 if (tmp != NULL)
783 if (tmp->len != 0)
784 return g_string_free (tmp, FALSE);
785 g_string_free (tmp, TRUE);
787 #endif
788 return g_strdup (str);
791 /* --------------------------------------------------------------------------------------------- */
793 static char *
794 edit_replace_cmd__conv_to_input (char *str)
796 #ifdef HAVE_CHARSET
797 GString *tmp;
799 tmp = str_convert_to_input (str);
800 if (tmp != NULL)
802 if (tmp->len != 0)
803 return g_string_free (tmp, FALSE);
804 g_string_free (tmp, TRUE);
806 #endif
807 return g_strdup (str);
810 /* --------------------------------------------------------------------------------------------- */
812 static void
813 edit_do_search (WEdit * edit)
815 gsize len = 0;
817 if (edit->search == NULL)
818 edit->search_start = edit->curs1;
820 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
822 if (search_create_bookmark)
824 int found = 0, books = 0;
825 long l = 0, l_last = -1;
826 long q = 0;
828 search_create_bookmark = FALSE;
829 book_mark_flush (edit, -1);
831 while (TRUE)
833 if (!mc_search_run (edit->search, (void *) edit, q, edit->last_byte, &len))
834 break;
835 if (found == 0)
836 edit->search_start = edit->search->normal_offset;
837 found++;
838 l += edit_count_lines (edit, q, edit->search->normal_offset);
839 if (l != l_last)
841 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
842 books++;
844 l_last = l;
845 q = edit->search->normal_offset + 1;
848 if (found == 0)
849 edit_error_dialog (_("Search"), _("Search string not found"));
850 else
851 edit_cursor_move (edit, edit->search_start - edit->curs1);
853 else
855 if (edit->found_len != 0 && edit->search_start == edit->found_start + 1
856 && edit_search_options.backwards)
857 edit->search_start--;
859 if (edit->found_len != 0 && edit->search_start == edit->found_start - 1
860 && !edit_search_options.backwards)
861 edit->search_start++;
863 if (editcmd_find (edit, &len))
865 edit->found_start = edit->search_start = edit->search->normal_offset;
866 edit->found_len = len;
867 edit->over_col = 0;
868 edit_cursor_move (edit, edit->search_start - edit->curs1);
869 edit_scroll_screen_over_cursor (edit);
870 if (edit_search_options.backwards)
871 edit->search_start--;
872 else
873 edit->search_start++;
875 else
877 edit->search_start = edit->curs1;
878 if (edit->search->error_str != NULL)
879 edit_error_dialog (_("Search"), edit->search->error_str);
883 edit->force |= REDRAW_COMPLETELY;
884 edit_scroll_screen_over_cursor (edit);
887 /* --------------------------------------------------------------------------------------------- */
889 static void
890 edit_search (WEdit * edit)
892 if (editcmd_dialog_search_show (edit))
893 edit_do_search (edit);
896 /* --------------------------------------------------------------------------------------------- */
897 /** Return a null terminated length of text. Result must be g_free'd */
899 static unsigned char *
900 edit_get_block (WEdit * edit, long start, long finish, int *l)
902 unsigned char *s, *r;
903 r = s = g_malloc0 (finish - start + 1);
904 if (edit->column_highlight)
906 *l = 0;
907 /* copy from buffer, excluding chars that are out of the column 'margins' */
908 while (start < finish)
910 int c;
911 long x;
912 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
913 c = edit_get_byte (edit, start);
914 if ((x >= edit->column1 && x < edit->column2)
915 || (x >= edit->column2 && x < edit->column1) || c == '\n')
917 *s++ = c;
918 (*l)++;
920 start++;
923 else
925 *l = finish - start;
926 while (start < finish)
927 *s++ = edit_get_byte (edit, start++);
929 *s = 0;
930 return r;
933 /* --------------------------------------------------------------------------------------------- */
934 /** copies a block to clipboard file */
936 static int
937 edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
939 int ret;
940 gchar *tmp;
941 tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_CLIP_FILE);
942 ret = edit_save_block (edit, tmp, start, finish);
943 g_free (tmp);
944 return ret;
947 /* --------------------------------------------------------------------------------------------- */
949 static void
950 pipe_mail (WEdit * edit, char *to, char *subject, char *cc)
952 FILE *p = 0;
953 char *s;
955 to = name_quote (to, 0);
956 subject = name_quote (subject, 0);
957 cc = name_quote (cc, 0);
958 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "", cc, " ", to, (char *) NULL);
959 g_free (to);
960 g_free (subject);
961 g_free (cc);
963 if (s)
965 p = popen (s, "w");
966 g_free (s);
969 if (p)
971 long i;
972 for (i = 0; i < edit->last_byte; i++)
973 fputc (edit_get_byte (edit, i), p);
974 pclose (p);
978 /* --------------------------------------------------------------------------------------------- */
980 static gboolean
981 is_break_char (char c)
983 return (isspace (c) || strchr ("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
986 /* --------------------------------------------------------------------------------------------- */
987 /** find first character of current word */
989 static int
990 edit_find_word_start (WEdit * edit, long *word_start, gsize * word_len)
992 int c, last;
993 gsize i;
995 /* return if at begin of file */
996 if (edit->curs1 <= 0)
997 return 0;
999 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
1000 /* return if not at end or in word */
1001 if (is_break_char (c))
1002 return 0;
1004 /* search start of word to be completed */
1005 for (i = 2;; i++)
1007 /* return if at begin of file */
1008 if ((gsize) edit->curs1 < i)
1009 return 0;
1011 last = c;
1012 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
1014 if (is_break_char (c))
1016 /* return if word starts with digit */
1017 if (isdigit (last))
1018 return 0;
1020 *word_start = edit->curs1 - (i - 1); /* start found */
1021 *word_len = i - 1;
1022 break;
1025 /* success */
1026 return 1;
1029 /* --------------------------------------------------------------------------------------------- */
1030 /** collect the possible completions */
1031 static gsize
1032 edit_collect_completions (WEdit * edit, long start, gsize word_len,
1033 char *match_expr, struct selection *compl, gsize * num)
1035 gsize len = 0;
1036 gsize max_len = 0;
1037 gsize i;
1038 int skip;
1039 GString *temp;
1040 mc_search_t *srch;
1042 long last_byte;
1044 srch = mc_search_new (match_expr, -1);
1045 if (srch == NULL)
1046 return 0;
1048 if (mc_config_get_bool
1049 (mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0))
1051 last_byte = edit->last_byte;
1053 else
1055 last_byte = start;
1058 srch->search_type = MC_SEARCH_T_REGEX;
1059 srch->is_case_sensitive = TRUE;
1060 srch->search_fn = edit_search_cmd_callback;
1062 /* collect max MAX_WORD_COMPLETIONS completions */
1063 start = -1;
1064 while (1)
1066 /* get next match */
1067 if (mc_search_run (srch, (void *) edit, start + 1, last_byte, &len) == FALSE)
1068 break;
1069 start = srch->normal_offset;
1071 /* add matched completion if not yet added */
1072 temp = g_string_new ("");
1073 for (i = 0; i < len; i++)
1075 skip = edit_get_byte (edit, start + i);
1076 if (isspace (skip))
1077 continue;
1078 g_string_append_c (temp, skip);
1081 skip = 0;
1083 for (i = 0; i < (gsize) * num; i++)
1085 if (strncmp
1086 ((char *) &compl[i].text[word_len],
1087 (char *) &temp->str[word_len], max (len, compl[i].len) - (gsize) word_len) == 0)
1089 struct selection this = compl[i];
1090 for (++i; i < *num; i++)
1092 compl[i - 1] = compl[i];
1094 compl[*num - 1] = this;
1095 skip = 1;
1096 break; /* skip it, already added */
1099 if (skip)
1101 g_string_free (temp, TRUE);
1102 continue;
1104 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS)
1106 g_free (compl[0].text);
1107 for (i = 1; i < *num; i++)
1109 compl[i - 1] = compl[i];
1111 (*num)--;
1113 #ifdef HAVE_CHARSET
1115 GString *recoded;
1116 recoded = str_convert_to_display (temp->str);
1118 if (recoded && recoded->len)
1120 g_string_free (temp, TRUE);
1121 temp = recoded;
1123 else
1124 g_string_free (recoded, TRUE);
1126 #endif
1127 compl[*num].text = temp->str;
1128 compl[*num].len = temp->len;
1129 (*num)++;
1130 start += len;
1131 g_string_free (temp, FALSE);
1133 /* note the maximal length needed for the completion dialog */
1134 if (len > max_len)
1135 max_len = len;
1137 mc_search_free (srch);
1138 return max_len;
1142 /* --------------------------------------------------------------------------------------------- */
1143 /*** public functions ****************************************************************************/
1144 /* --------------------------------------------------------------------------------------------- */
1146 void
1147 edit_help_cmd (WEdit * edit)
1149 ev_help_t event_data = { NULL, "[Internal File Editor]" };
1150 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
1152 edit->force |= REDRAW_COMPLETELY;
1155 /* --------------------------------------------------------------------------------------------- */
1157 void
1158 edit_refresh_cmd (WEdit * edit)
1160 #ifdef HAVE_SLANG
1161 int color;
1163 edit_get_syntax_color (edit, -1, &color);
1164 tty_touch_screen ();
1165 mc_refresh ();
1166 #else
1167 (void) edit;
1169 clr_scr ();
1170 repaint_screen ();
1171 #endif /* !HAVE_SLANG */
1172 tty_keypad (TRUE);
1175 /* --------------------------------------------------------------------------------------------- */
1177 void
1178 menu_save_mode_cmd (void)
1180 /* diaog sizes */
1181 const int DLG_X = 38;
1182 const int DLG_Y = 13;
1184 char *str_result;
1186 const char *str[] = {
1187 N_("&Quick save"),
1188 N_("&Safe save"),
1189 N_("&Do backups with following extension:")
1192 QuickWidget widgets[] = {
1193 /* 0 */
1194 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
1195 /* 1 */
1196 QUICK_BUTTON (6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
1197 /* 2 */
1198 QUICK_CHECKBOX (4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
1199 /* 3 */
1200 QUICK_INPUT (8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
1201 /* 4 */
1202 QUICK_RADIO (4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
1203 QUICK_END
1206 QuickDialog dialog = {
1207 DLG_X, DLG_Y, -1, -1, N_("Edit Save Mode"),
1208 "[Edit Save Mode]", widgets, NULL, FALSE
1211 size_t i;
1212 size_t maxlen = 0;
1213 size_t w0, w1, b_len, w3;
1215 assert (option_backup_ext != NULL);
1217 /* OK/Cancel buttons */
1218 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
1219 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
1220 b_len = w0 + w1 + 3;
1222 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
1224 w3 = 0;
1225 for (i = 0; i < 3; i++)
1227 #ifdef ENABLE_NLS
1228 str[i] = _(str[i]);
1229 #endif
1230 w3 = max (w3, (size_t) str_term_width1 (str[i]));
1233 maxlen = max (maxlen, w3 + 4);
1235 dialog.xlen = min ((size_t) COLS, maxlen + 8);
1237 widgets[3].u.input.len = w3;
1238 widgets[1].relative_x = (dialog.xlen - b_len) / 2;
1239 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
1241 for (i = 0; i < sizeof (widgets) / sizeof (widgets[0]); i++)
1242 widgets[i].x_divisions = dialog.xlen;
1244 if (quick_dialog (&dialog) != B_CANCEL)
1246 g_free (option_backup_ext);
1247 option_backup_ext = str_result;
1251 /* --------------------------------------------------------------------------------------------- */
1253 void
1254 edit_set_filename (WEdit * edit, const char *name)
1256 g_free (edit->filename);
1258 if (name == NULL)
1259 name = "";
1261 edit->filename = tilde_expand (name);
1262 if (edit->dir == NULL && !g_path_is_absolute (name))
1263 edit->dir = vfs_get_current_dir ();
1266 /* --------------------------------------------------------------------------------------------- */
1267 /* Here we want to warn the users of overwriting an existing file,
1268 but only if they have made a change to the filename */
1269 /* returns 1 on success */
1271 edit_save_as_cmd (WEdit * edit)
1273 /* This heads the 'Save As' dialog box */
1274 char *exp;
1275 int save_lock = 0;
1276 int different_filename = 0;
1278 if (!edit_check_newline (edit))
1279 return 0;
1281 exp = edit_get_save_file_as (edit);
1282 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1284 if (exp)
1286 if (!*exp)
1288 g_free (exp);
1289 edit->force |= REDRAW_COMPLETELY;
1290 return 0;
1292 else
1294 int rv;
1295 if (strcmp (edit->filename, exp))
1297 int file;
1298 different_filename = 1;
1299 file = mc_open (exp, O_RDONLY | O_BINARY);
1300 if (file != -1)
1302 /* the file exists */
1303 mc_close (file);
1304 /* Overwrite the current file or cancel the operation */
1305 if (edit_query_dialog2
1306 (_("Warning"),
1307 _("A file already exists with this name"), _("&Overwrite"), _("&Cancel")))
1309 edit->force |= REDRAW_COMPLETELY;
1310 g_free (exp);
1311 return 0;
1314 else
1316 edit->stat1.st_mode |= S_IWUSR;
1318 save_lock = lock_file (exp);
1320 else
1322 /* filenames equal, check if already locked */
1323 if (!edit->locked && !edit->delete_file)
1324 save_lock = lock_file (exp);
1327 if (different_filename)
1330 * Allow user to write into saved (under another name) file
1331 * even if original file had r/o user permissions.
1333 edit->stat1.st_mode |= S_IWRITE;
1336 rv = edit_save_file (edit, exp);
1337 switch (rv)
1339 case 1:
1340 /* Succesful, so unlock both files */
1341 if (different_filename)
1343 if (save_lock)
1344 unlock_file (exp);
1345 if (edit->locked)
1346 edit->locked = edit_unlock_file (edit);
1348 else
1350 if (edit->locked || save_lock)
1351 edit->locked = edit_unlock_file (edit);
1354 edit_set_filename (edit, exp);
1355 if (edit->lb != LB_ASIS)
1356 edit_reload (edit, exp);
1357 g_free (exp);
1358 edit->modified = 0;
1359 edit->delete_file = 0;
1360 if (different_filename)
1361 edit_load_syntax (edit, NULL, edit->syntax_type);
1362 edit->force |= REDRAW_COMPLETELY;
1363 return 1;
1364 default:
1365 edit_error_dialog (_("Save as"), get_sys_error (_("Cannot save file")));
1366 /* fallthrough */
1367 case -1:
1368 /* Failed, so maintain modify (not save) lock */
1369 if (save_lock)
1370 unlock_file (exp);
1371 g_free (exp);
1372 edit->force |= REDRAW_COMPLETELY;
1373 return 0;
1377 edit->force |= REDRAW_COMPLETELY;
1378 return 0;
1381 /* {{{ Macro stuff starts here */
1383 /* --------------------------------------------------------------------------------------------- */
1385 static int
1386 edit_macro_comparator (gconstpointer * macro1, gconstpointer * macro2)
1388 const macros_t *m1 = (const macros_t *) macro1;
1389 const macros_t *m2 = (const macros_t *) macro2;
1391 return m1->hotkey - m2->hotkey;
1394 /* --------------------------------------------------------------------------------------------- */
1396 static void
1397 edit_macro_sort_by_hotkey (void)
1399 if (macros_list != NULL && macros_list->len != 0)
1400 g_array_sort (macros_list, (GCompareFunc) edit_macro_comparator);
1403 /* --------------------------------------------------------------------------------------------- */
1405 static gboolean
1406 edit_get_macro (WEdit * edit, int hotkey, const macros_t ** macros, guint * indx)
1408 const macros_t *array_start = &g_array_index (macros_list, struct macros_t, 0);
1409 macros_t *result;
1410 macros_t search_macro;
1412 (void) edit;
1414 search_macro.hotkey = hotkey;
1415 result = bsearch (&search_macro, macros_list->data, macros_list->len,
1416 sizeof (macros_t), (GCompareFunc) edit_macro_comparator);
1418 if (result != NULL && result->macro != NULL)
1420 *indx = (result - array_start);
1421 *macros = result;
1422 return TRUE;
1424 *indx = 0;
1425 return FALSE;
1428 /* --------------------------------------------------------------------------------------------- */
1429 /** returns FALSE on error */
1431 static gboolean
1432 edit_delete_macro (WEdit * edit, int hotkey)
1434 mc_config_t *macros_config = NULL;
1435 const char *section_name = "editor";
1436 gchar *macros_fname;
1437 guint indx;
1438 char *keyname;
1439 const macros_t *macros = NULL;
1441 /* clear array of actions for current hotkey */
1442 while (edit_get_macro (edit, hotkey, &macros, &indx))
1444 if (macros->macro != NULL)
1445 g_array_free (macros->macro, TRUE);
1446 macros = NULL;
1447 g_array_remove_index (macros_list, indx);
1448 edit_macro_sort_by_hotkey ();
1451 macros_fname = g_build_filename (mc_config_get_data_path (), MC_MACRO_FILE, (char *) NULL);
1452 macros_config = mc_config_init (macros_fname);
1453 g_free (macros_fname);
1455 if (macros_config == NULL)
1456 return FALSE;
1458 keyname = lookup_key_by_code (hotkey);
1459 while (mc_config_del_key (macros_config, section_name, keyname))
1461 g_free (keyname);
1462 mc_config_save_file (macros_config, NULL);
1463 mc_config_deinit (macros_config);
1464 return TRUE;
1467 /* --------------------------------------------------------------------------------------------- */
1469 void
1470 edit_delete_macro_cmd (WEdit * edit)
1472 int hotkey;
1474 hotkey = editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), 1);
1476 if (hotkey != 0 && !edit_delete_macro (edit, hotkey))
1477 message (D_ERROR, _("Delete macro"), _("Macro not deleted"));
1480 /* --------------------------------------------------------------------------------------------- */
1482 /** returns FALSE on error */
1483 gboolean
1484 edit_execute_macro (WEdit * edit, int hotkey)
1486 gboolean res = FALSE;
1488 if (hotkey != 0)
1490 const macros_t *macros;
1491 guint indx;
1493 if (edit_get_macro (edit, hotkey, &macros, &indx) &&
1494 macros->macro != NULL && macros->macro->len != 0)
1496 guint i;
1498 edit->force |= REDRAW_PAGE;
1500 for (i = 0; i < macros->macro->len; i++)
1502 const macro_action_t *m_act;
1504 m_act = &g_array_index (macros->macro, struct macro_action_t, i);
1505 edit_execute_cmd (edit, m_act->action, m_act->ch);
1506 res = TRUE;
1510 edit_update_screen (edit);
1511 return res;
1514 /* --------------------------------------------------------------------------------------------- */
1516 /** returns FALSE on error */
1517 gboolean
1518 edit_store_macro_cmd (WEdit * edit)
1520 int i;
1521 int hotkey;
1522 GString *marcros_string;
1523 mc_config_t *macros_config = NULL;
1524 const char *section_name = "editor";
1525 gchar *macros_fname;
1526 GArray *macros; /* current macro */
1527 int tmp_act;
1528 gboolean have_macro = FALSE;
1529 char *keyname = NULL;
1531 hotkey = editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), 1);
1532 if (hotkey == ESC_CHAR)
1533 return FALSE;
1535 tmp_act = keybind_lookup_keymap_command (editor_map, hotkey);
1537 /* return FALSE if try assign macro into restricted hotkeys */
1538 if (tmp_act == CK_MacroStartRecord
1539 || tmp_act == CK_MacroStopRecord || tmp_act == CK_MacroStartStopRecord)
1540 return FALSE;
1542 edit_delete_macro (edit, hotkey);
1544 macros_fname = g_build_filename (mc_config_get_data_path (), MC_MACRO_FILE, (char *) NULL);
1545 macros_config = mc_config_init (macros_fname);
1546 g_free (macros_fname);
1548 if (macros_config == NULL)
1549 return FALSE;
1551 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1553 marcros_string = g_string_sized_new (250);
1554 macros = g_array_new (TRUE, FALSE, sizeof (macro_action_t));
1556 keyname = lookup_key_by_code (hotkey);
1558 for (i = 0; i < macro_index; i++)
1560 macro_action_t m_act;
1561 const char *action_name;
1563 action_name = keybind_lookup_actionname (record_macro_buf[i].action);
1565 if (action_name == NULL)
1566 break;
1568 m_act.action = record_macro_buf[i].action;
1569 m_act.ch = record_macro_buf[i].ch;
1570 g_array_append_val (macros, m_act);
1571 have_macro = TRUE;
1572 g_string_append_printf (marcros_string, "%s:%i;", action_name,
1573 (int) record_macro_buf[i].ch);
1575 if (have_macro)
1577 macros_t macro;
1578 macro.hotkey = hotkey;
1579 macro.macro = macros;
1580 g_array_append_val (macros_list, macro);
1581 mc_config_set_string (macros_config, section_name, keyname, marcros_string->str);
1583 else
1584 mc_config_del_key (macros_config, section_name, keyname);
1586 g_free (keyname);
1587 edit_macro_sort_by_hotkey ();
1589 g_string_free (marcros_string, TRUE);
1590 mc_config_save_file (macros_config, NULL);
1591 mc_config_deinit (macros_config);
1592 return TRUE;
1595 /* --------------------------------------------------------------------------------------------- */
1597 gboolean
1598 edit_repeat_macro_cmd (WEdit * edit)
1600 int i, j;
1601 char *f;
1602 long count_repeat;
1603 char *error = NULL;
1605 f = input_dialog (_("Repeat last commands"), _("Repeat times:"), MC_HISTORY_EDIT_REPEAT, NULL);
1606 if (f == NULL || *f == '\0')
1608 g_free (f);
1609 return FALSE;
1612 count_repeat = strtol (f, &error, 0);
1614 if (*error != '\0')
1616 g_free (f);
1617 return FALSE;
1620 g_free (f);
1622 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1623 edit->force |= REDRAW_PAGE;
1625 for (j = 0; j < count_repeat; j++)
1626 for (i = 0; i < macro_index; i++)
1627 edit_execute_cmd (edit, record_macro_buf[i].action, record_macro_buf[i].ch);
1628 edit_update_screen (edit);
1629 return TRUE;
1632 /* --------------------------------------------------------------------------------------------- */
1633 /** return FALSE on error */
1635 gboolean
1636 edit_load_macro_cmd (WEdit * edit)
1638 mc_config_t *macros_config = NULL;
1639 gchar **profile_keys, **keys;
1640 gchar **values, **curr_values;
1641 gsize len, values_len;
1642 const char *section_name = "editor";
1643 gchar *macros_fname;
1644 int hotkey;
1646 (void) edit;
1648 macros_fname = g_build_filename (mc_config_get_data_path (), MC_MACRO_FILE, (char *) NULL);
1649 macros_config = mc_config_init (macros_fname);
1650 g_free (macros_fname);
1652 if (macros_config == NULL)
1653 return FALSE;
1655 profile_keys = keys = mc_config_get_keys (macros_config, section_name, &len);
1656 while (*profile_keys != NULL)
1658 gboolean have_macro;
1659 GArray *macros;
1660 macros_t macro;
1662 macros = g_array_new (TRUE, FALSE, sizeof (macro_action_t));
1664 curr_values = values = mc_config_get_string_list (macros_config, section_name,
1665 *profile_keys, &values_len);
1666 hotkey = lookup_key (*profile_keys, NULL);
1667 have_macro = FALSE;
1669 while (*curr_values != NULL && *curr_values[0] != '\0')
1671 char **macro_pair = NULL;
1673 macro_pair = g_strsplit (*curr_values, ":", 2);
1675 if (macro_pair != NULL)
1677 macro_action_t m_act;
1678 if (macro_pair[0] == NULL || macro_pair[0][0] == '\0')
1679 m_act.action = 0;
1680 else
1682 m_act.action = keybind_lookup_action (macro_pair[0]);
1683 g_free (macro_pair[0]);
1684 macro_pair[0] = NULL;
1686 if (macro_pair[1] == NULL || macro_pair[1][0] == '\0')
1687 m_act.ch = -1;
1688 else
1690 m_act.ch = strtol (macro_pair[1], NULL, 0);
1691 g_free (macro_pair[1]);
1692 macro_pair[1] = NULL;
1694 if (m_act.action != 0)
1696 /* a shell command */
1697 if ((m_act.action / CK_PipeBlock (0)) == 1)
1699 m_act.action = CK_PipeBlock (0) + (m_act.ch > 0 ? m_act.ch : 0);
1700 m_act.ch = -1;
1702 g_array_append_val (macros, m_act);
1703 have_macro = TRUE;
1705 g_strfreev (macro_pair);
1706 macro_pair = NULL;
1708 curr_values++;
1710 if (have_macro)
1712 macro.hotkey = hotkey;
1713 macro.macro = macros;
1714 g_array_append_val (macros_list, macro);
1716 profile_keys++;
1717 g_strfreev (values);
1719 g_strfreev (keys);
1720 mc_config_deinit (macros_config);
1721 edit_macro_sort_by_hotkey ();
1722 return TRUE;
1725 /* }}} Macro stuff end here */
1727 /* --------------------------------------------------------------------------------------------- */
1728 /** returns 1 on success */
1731 edit_save_confirm_cmd (WEdit * edit)
1733 gchar *f = NULL;
1735 if (!edit_check_newline (edit))
1736 return 0;
1738 if (edit_confirm_save)
1740 f = g_strdup_printf (_("Confirm save file: \"%s\""), edit->filename);
1741 if (edit_query_dialog2 (_("Save file"), f, _("&Save"), _("&Cancel")))
1743 g_free (f);
1744 return 0;
1746 g_free (f);
1748 return edit_save_cmd (edit);
1751 /* --------------------------------------------------------------------------------------------- */
1752 /** returns 1 on success */
1755 edit_new_cmd (WEdit * edit)
1757 if (edit->modified)
1759 if (edit_query_dialog2
1760 (_("Warning"),
1762 ("Current text was modified without a file save.\nContinue discards these changes"),
1763 _("C&ontinue"), _("&Cancel")))
1765 edit->force |= REDRAW_COMPLETELY;
1766 return 0;
1769 edit->force |= REDRAW_COMPLETELY;
1771 return edit_renew (edit); /* if this gives an error, something has really screwed up */
1774 /* --------------------------------------------------------------------------------------------- */
1777 edit_load_cmd (WEdit * edit, edit_current_file_t what)
1779 char *exp;
1781 if (edit->modified
1782 && (edit_query_dialog2
1783 (_("Warning"),
1784 _("Current text was modified without a file save.\n"
1785 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")) == 1))
1787 edit->force |= REDRAW_COMPLETELY;
1788 return 0;
1791 switch (what)
1793 case EDIT_FILE_COMMON:
1794 exp = input_expand_dialog (_("Load"), _("Enter file name:"),
1795 MC_HISTORY_EDIT_LOAD, edit->filename);
1797 if (exp)
1799 if (*exp)
1800 edit_load_file_from_filename (edit, exp);
1801 g_free (exp);
1803 break;
1805 case EDIT_FILE_SYNTAX:
1806 edit_load_syntax_file (edit);
1807 break;
1809 case EDIT_FILE_MENU:
1810 edit_load_menu_file (edit);
1811 break;
1813 default:
1814 break;
1817 edit->force |= REDRAW_COMPLETELY;
1818 return 0;
1821 /* --------------------------------------------------------------------------------------------- */
1823 if mark2 is -1 then marking is from mark1 to the cursor.
1824 Otherwise its between the markers. This handles this.
1825 Returns 1 if no text is marked.
1829 eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1831 if (edit->mark1 != edit->mark2)
1833 long start_bol, start_eol;
1834 long end_bol, end_eol;
1835 long col1, col2;
1836 long diff1, diff2;
1837 long end_mark_curs;
1839 if (edit->end_mark_curs < 0)
1840 end_mark_curs = edit->curs1;
1841 else
1842 end_mark_curs = edit->end_mark_curs;
1844 if (edit->mark2 >= 0)
1846 *start_mark = min (edit->mark1, edit->mark2);
1847 *end_mark = max (edit->mark1, edit->mark2);
1849 else
1851 *start_mark = min (edit->mark1, end_mark_curs);
1852 *end_mark = max (edit->mark1, end_mark_curs);
1853 edit->column2 = edit->curs_col + edit->over_col;
1856 if (edit->column_highlight
1857 && (((edit->mark1 > end_mark_curs) && (edit->column1 < edit->column2))
1858 || ((edit->mark1 < end_mark_curs) && (edit->column1 > edit->column2))))
1860 start_bol = edit_bol (edit, *start_mark);
1861 start_eol = edit_eol (edit, start_bol - 1) + 1;
1862 end_bol = edit_bol (edit, *end_mark);
1863 end_eol = edit_eol (edit, *end_mark);
1864 col1 = min (edit->column1, edit->column2);
1865 col2 = max (edit->column1, edit->column2);
1867 diff1 =
1868 edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol,
1869 col1, 0);
1870 diff2 =
1871 edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol,
1872 col1, 0);
1874 *start_mark -= diff1;
1875 *end_mark += diff2;
1876 *start_mark = max (*start_mark, start_eol);
1877 *end_mark = min (*end_mark, end_eol);
1879 return 0;
1881 else
1883 *start_mark = *end_mark = 0;
1884 edit->column2 = edit->column1 = 0;
1885 return 1;
1889 /* --------------------------------------------------------------------------------------------- */
1891 void
1892 edit_insert_over (WEdit * edit)
1894 int i;
1896 for (i = 0; i < edit->over_col; i++)
1898 edit_insert (edit, ' ');
1900 edit->over_col = 0;
1903 /* --------------------------------------------------------------------------------------------- */
1905 void
1906 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width,
1907 long *start_pos, long *end_pos, int *col1, int *col2)
1909 long cursor;
1910 int i, col;
1912 cursor = edit->curs1;
1913 col = edit_get_col (edit);
1914 for (i = 0; i < size; i++)
1916 if (data[i] == '\n')
1917 { /* fill in and move to next line */
1918 int l;
1919 long p;
1920 if (edit_get_byte (edit, edit->curs1) != '\n')
1922 l = width - (edit_get_col (edit) - col);
1923 while (l > 0)
1925 edit_insert (edit, ' ');
1926 l -= space_width;
1929 for (p = edit->curs1;; p++)
1931 if (p == edit->last_byte)
1933 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1934 edit_insert_ahead (edit, '\n');
1935 p++;
1936 break;
1938 if (edit_get_byte (edit, p) == '\n')
1940 p++;
1941 break;
1944 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1945 l = col - edit_get_col (edit);
1946 while (l >= space_width)
1948 edit_insert (edit, ' ');
1949 l -= space_width;
1951 continue;
1953 edit_insert (edit, data[i]);
1955 *col1 = col;
1956 *col2 = col + width;
1957 *start_pos = cursor;
1958 *end_pos = edit->curs1;
1959 edit_cursor_move (edit, cursor - edit->curs1);
1962 /* --------------------------------------------------------------------------------------------- */
1965 edit_insert_column_of_text_from_file (WEdit * edit, int file,
1966 long *start_pos, long *end_pos, int *col1, int *col2)
1968 long cursor;
1969 int col;
1970 int blocklen = -1, width = 0;
1971 unsigned char *data;
1973 cursor = edit->curs1;
1974 col = edit_get_col (edit);
1975 data = g_malloc0 (TEMP_BUF_LEN);
1977 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0)
1979 int i;
1980 for (width = 0; width < blocklen; width++)
1982 if (data[width] == '\n')
1983 break;
1985 for (i = 0; i < blocklen; i++)
1987 if (data[i] == '\n')
1988 { /* fill in and move to next line */
1989 int l;
1990 long p;
1991 if (edit_get_byte (edit, edit->curs1) != '\n')
1993 l = width - (edit_get_col (edit) - col);
1994 while (l > 0)
1996 edit_insert (edit, ' ');
1997 l -= space_width;
2000 for (p = edit->curs1;; p++)
2002 if (p == edit->last_byte)
2004 edit_cursor_move (edit, edit->last_byte - edit->curs1);
2005 edit_insert_ahead (edit, '\n');
2006 p++;
2007 break;
2009 if (edit_get_byte (edit, p) == '\n')
2011 p++;
2012 break;
2015 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
2016 l = col - edit_get_col (edit);
2017 while (l >= space_width)
2019 edit_insert (edit, ' ');
2020 l -= space_width;
2022 continue;
2024 edit_insert (edit, data[i]);
2027 *col1 = col;
2028 *col2 = col + width;
2029 *start_pos = cursor;
2030 *end_pos = edit->curs1;
2031 edit_cursor_move (edit, cursor - edit->curs1);
2032 g_free (data);
2034 return blocklen;
2037 /* --------------------------------------------------------------------------------------------- */
2039 void
2040 edit_block_copy_cmd (WEdit * edit)
2042 long start_mark, end_mark, current = edit->curs1;
2043 long col_delta = 0;
2044 long mark1, mark2;
2045 int c1, c2;
2046 int size;
2047 unsigned char *copy_buf;
2049 edit_update_curs_col (edit);
2050 if (eval_marks (edit, &start_mark, &end_mark))
2051 return;
2053 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
2055 /* all that gets pushed are deletes hence little space is used on the stack */
2057 edit_push_markers (edit);
2059 if (edit->column_highlight)
2061 col_delta = abs (edit->column2 - edit->column1);
2062 edit_insert_column_of_text (edit, copy_buf, size, col_delta, &mark1, &mark2, &c1, &c2);
2064 else
2066 while (size--)
2067 edit_insert_ahead (edit, copy_buf[size]);
2070 g_free (copy_buf);
2071 edit_scroll_screen_over_cursor (edit);
2073 if (edit->column_highlight)
2074 edit_set_markers (edit, edit->curs1, mark2, c1, c2);
2075 else if (start_mark < current && end_mark > current)
2076 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
2078 edit->force |= REDRAW_PAGE;
2082 /* --------------------------------------------------------------------------------------------- */
2084 void
2085 edit_block_move_cmd (WEdit * edit)
2087 long current;
2088 unsigned char *copy_buf = NULL;
2089 long start_mark, end_mark;
2090 long line;
2092 if (eval_marks (edit, &start_mark, &end_mark))
2093 return;
2095 line = edit->curs_line;
2096 if (edit->mark2 < 0)
2097 edit_mark_cmd (edit, 0);
2098 edit_push_markers (edit);
2100 if (edit->column_highlight)
2102 long mark1, mark2;
2103 int size;
2104 int b_width = 0;
2105 int c1, c2;
2106 int x, x2;
2108 c1 = min (edit->column1, edit->column2);
2109 c2 = max (edit->column1, edit->column2);
2110 b_width = (c2 - c1);
2112 edit_update_curs_col (edit);
2114 x = edit->curs_col;
2115 x2 = x + edit->over_col;
2117 /* do nothing when cursor inside first line of selected area */
2118 if ((edit_eol (edit, edit->curs1) == edit_eol (edit, start_mark)) && (x2 > c1 && x2 <= c2))
2119 return;
2121 if (edit->curs1 > start_mark && edit->curs1 < edit_eol (edit, end_mark))
2123 if (x > c2)
2124 x -= b_width;
2125 else if (x > c1 && x <= c2)
2126 x = c1;
2128 /* save current selection into buffer */
2129 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
2131 /* remove current selection */
2132 edit_block_delete_cmd (edit);
2134 edit->over_col = max (0, edit->over_col - b_width);
2135 /* calculate the cursor pos after delete block */
2136 current = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), x, 0);
2137 edit_cursor_move (edit, current - edit->curs1);
2138 edit_scroll_screen_over_cursor (edit);
2140 /* add TWS if need before block insertion */
2141 if (option_cursor_beyond_eol && edit->over_col > 0)
2142 edit_insert_over (edit);
2144 edit_insert_column_of_text (edit, copy_buf, size, b_width, &mark1, &mark2, &c1, &c2);
2145 edit_set_markers (edit, mark1, mark2, c1, c2);
2147 else
2149 long count;
2151 current = edit->curs1;
2152 copy_buf = g_malloc0 (end_mark - start_mark);
2153 edit_cursor_move (edit, start_mark - edit->curs1);
2154 edit_scroll_screen_over_cursor (edit);
2155 count = start_mark;
2156 while (count < end_mark)
2158 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
2159 count++;
2161 edit_scroll_screen_over_cursor (edit);
2162 edit_cursor_move (edit,
2163 current - edit->curs1 -
2164 (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
2165 edit_scroll_screen_over_cursor (edit);
2166 while (count-- > start_mark)
2167 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
2168 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
2171 edit_scroll_screen_over_cursor (edit);
2172 g_free (copy_buf);
2173 edit->force |= REDRAW_PAGE;
2176 /* --------------------------------------------------------------------------------------------- */
2177 /** returns 1 if canceelled by user */
2180 edit_block_delete_cmd (WEdit * edit)
2182 long start_mark, end_mark;
2183 if (eval_marks (edit, &start_mark, &end_mark))
2185 edit_delete_line (edit);
2186 return 0;
2188 return edit_block_delete (edit);
2191 /* --------------------------------------------------------------------------------------------- */
2192 /** call with edit = 0 before shutdown to close memory leaks */
2194 void
2195 edit_replace_cmd (WEdit * edit, int again)
2197 /* 1 = search string, 2 = replace with */
2198 static char *saved1 = NULL; /* saved default[123] */
2199 static char *saved2 = NULL;
2200 char *input1 = NULL; /* user input from the dialog */
2201 char *input2 = NULL;
2202 char *disp1 = NULL;
2203 char *disp2 = NULL;
2204 long times_replaced = 0;
2205 gboolean once_found = FALSE;
2207 if (!edit)
2209 g_free (saved1), saved1 = NULL;
2210 g_free (saved2), saved2 = NULL;
2211 return;
2214 edit->force |= REDRAW_COMPLETELY;
2216 if (again && !saved1 && !saved2)
2217 again = 0;
2219 if (again)
2221 input1 = g_strdup (saved1 ? saved1 : "");
2222 input2 = g_strdup (saved2 ? saved2 : "");
2224 else
2226 char *tmp_inp1, *tmp_inp2;
2227 disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
2228 disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
2230 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
2232 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2);
2234 g_free (disp1);
2235 g_free (disp2);
2237 if (input1 == NULL || *input1 == '\0')
2239 edit->force = REDRAW_COMPLETELY;
2240 goto cleanup;
2243 tmp_inp1 = input1;
2244 tmp_inp2 = input2;
2245 input1 = edit_replace_cmd__conv_to_input (input1);
2246 input2 = edit_replace_cmd__conv_to_input (input2);
2247 g_free (tmp_inp1);
2248 g_free (tmp_inp2);
2250 g_free (saved1), saved1 = g_strdup (input1);
2251 g_free (saved2), saved2 = g_strdup (input2);
2253 mc_search_free (edit->search);
2254 edit->search = NULL;
2257 if (!edit->search)
2259 edit->search = mc_search_new (input1, -1);
2260 if (edit->search == NULL)
2262 edit->search_start = edit->curs1;
2263 goto cleanup;
2265 edit->search->search_type = edit_search_options.type;
2266 edit->search->is_all_charsets = edit_search_options.all_codepages;
2267 edit->search->is_case_sensitive = edit_search_options.case_sens;
2268 edit->search->whole_words = edit_search_options.whole_words;
2269 edit->search->search_fn = edit_search_cmd_callback;
2272 if (edit->found_len && edit->search_start == edit->found_start + 1
2273 && edit_search_options.backwards)
2274 edit->search_start--;
2276 if (edit->found_len && edit->search_start == edit->found_start - 1
2277 && !edit_search_options.backwards)
2278 edit->search_start++;
2282 gsize len = 0;
2284 if (!editcmd_find (edit, &len))
2286 if (!(edit->search->error == MC_SEARCH_E_OK ||
2287 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
2289 edit_error_dialog (_("Search"), edit->search->error_str);
2291 break;
2293 once_found = TRUE;
2295 edit->search_start = edit->search->normal_offset;
2296 /*returns negative on not found or error in pattern */
2298 if ((edit->search_start >= 0) && (edit->search_start < edit->last_byte))
2300 gsize i;
2301 GString *tmp_str, *repl_str;
2303 edit->found_start = edit->search_start;
2304 i = edit->found_len = len;
2306 edit_cursor_move (edit, edit->search_start - edit->curs1);
2307 edit_scroll_screen_over_cursor (edit);
2309 if (edit->replace_mode == 0)
2311 int l;
2312 int prompt;
2314 l = edit->curs_row - edit->widget.lines / 3;
2315 if (l > 0)
2316 edit_scroll_downward (edit, l);
2317 if (l < 0)
2318 edit_scroll_upward (edit, -l);
2320 edit_scroll_screen_over_cursor (edit);
2321 edit->force |= REDRAW_PAGE;
2322 edit_render_keypress (edit);
2324 /*so that undo stops at each query */
2325 edit_push_key_press (edit);
2326 /* and prompt 2/3 down */
2327 disp1 = edit_replace_cmd__conv_to_display (saved1);
2328 disp2 = edit_replace_cmd__conv_to_display (saved2);
2329 prompt = editcmd_dialog_replace_prompt_show (edit, disp1, disp2, -1, -1);
2330 g_free (disp1);
2331 g_free (disp2);
2333 if (prompt == B_REPLACE_ALL)
2334 edit->replace_mode = 1;
2335 else if (prompt == B_SKIP_REPLACE)
2337 if (edit_search_options.backwards)
2338 edit->search_start--;
2339 else
2340 edit->search_start++;
2341 continue; /* loop */
2343 else if (prompt == B_CANCEL)
2345 edit->replace_mode = -1;
2346 break; /* loop */
2350 /* don't process string each time */
2351 tmp_str = g_string_new (input2);
2352 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
2353 g_string_free (tmp_str, TRUE);
2355 if (edit->search->error != MC_SEARCH_E_OK)
2357 edit_error_dialog (_("Replace"), edit->search->error_str);
2358 g_string_free (repl_str, TRUE);
2359 break;
2362 /* delete then insert new */
2363 for (i = 0; i < len; i++)
2364 edit_delete (edit, 1);
2366 for (i = 0; i < repl_str->len; i++)
2367 edit_insert (edit, repl_str->str[i]);
2369 edit->found_len = repl_str->len;
2370 g_string_free (repl_str, TRUE);
2371 times_replaced++;
2373 /* so that we don't find the same string again */
2374 if (edit_search_options.backwards)
2375 edit->search_start--;
2376 else
2378 edit->search_start += edit->found_len;
2380 if (edit->search_start >= edit->last_byte)
2381 break;
2384 edit_scroll_screen_over_cursor (edit);
2386 else
2388 /* try and find from right here for next search */
2389 edit->search_start = edit->curs1;
2390 edit_update_curs_col (edit);
2392 edit->force |= REDRAW_PAGE;
2393 edit_render_keypress (edit);
2395 if (times_replaced == 0)
2396 query_dialog (_("Replace"), _("Search string not found"), D_NORMAL, 1, _("&OK"));
2397 break;
2400 while (edit->replace_mode >= 0);
2402 edit_scroll_screen_over_cursor (edit);
2403 edit->force |= REDRAW_COMPLETELY;
2404 edit_render_keypress (edit);
2406 if ((edit->replace_mode == 1) && (times_replaced != 0))
2407 message (D_NORMAL, _("Replace"), _("%ld replacements made"), times_replaced);
2409 cleanup:
2410 g_free (input1);
2411 g_free (input2);
2414 /* --------------------------------------------------------------------------------------------- */
2417 edit_search_cmd_callback (const void *user_data, gsize char_offset)
2419 return edit_get_byte ((WEdit *) user_data, (long) char_offset);
2422 /* --------------------------------------------------------------------------------------------- */
2424 void
2425 edit_search_cmd (WEdit * edit, gboolean again)
2427 if (edit == NULL)
2428 return;
2430 if (!again)
2431 edit_search (edit);
2432 else if (edit->last_search_string != NULL)
2433 edit_do_search (edit);
2434 else
2436 /* find last search string in history */
2437 GList *history;
2439 history = history_get (MC_HISTORY_SHARED_SEARCH);
2440 if (history != NULL && history->data != NULL)
2442 edit->last_search_string = (char *) history->data;
2443 history->data = NULL;
2444 history = g_list_first (history);
2445 g_list_foreach (history, (GFunc) g_free, NULL);
2446 g_list_free (history);
2448 edit->search = mc_search_new (edit->last_search_string, -1);
2449 if (edit->search == NULL)
2451 /* if not... then ask for an expression */
2452 g_free (edit->last_search_string);
2453 edit->last_search_string = NULL;
2454 edit_search (edit);
2456 else
2458 edit->search->search_type = edit_search_options.type;
2459 edit->search->is_all_charsets = edit_search_options.all_codepages;
2460 edit->search->is_case_sensitive = edit_search_options.case_sens;
2461 edit->search->whole_words = edit_search_options.whole_words;
2462 edit->search->search_fn = edit_search_cmd_callback;
2463 edit_do_search (edit);
2466 else
2468 /* if not... then ask for an expression */
2469 g_free (edit->last_search_string);
2470 edit->last_search_string = NULL;
2471 edit_search (edit);
2477 /* --------------------------------------------------------------------------------------------- */
2479 * Check if it's OK to close the editor. If there are unsaved changes,
2480 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2483 gboolean
2484 edit_ok_to_exit (WEdit * edit)
2486 int act;
2488 if (!edit->modified)
2489 return TRUE;
2491 if (!mc_global.widget.midnight_shutdown)
2493 if (!edit_check_newline (edit))
2494 return FALSE;
2496 query_set_sel (2);
2497 act = edit_query_dialog3 (_("Quit"), _("File was modified. Save with exit?"),
2498 _("&Yes"), _("&No"), _("&Cancel quit"));
2500 else
2502 act =
2503 edit_query_dialog2 (_("Quit"),
2504 _("Midnight Commander is being shut down.\nSave modified file?"),
2505 _("&Yes"), _("&No"));
2507 /* Esc is No */
2508 if (act == -1)
2509 act = 1;
2512 switch (act)
2514 case 0: /* Yes */
2515 edit_push_markers (edit);
2516 edit_set_markers (edit, 0, 0, 0, 0);
2517 if (!edit_save_cmd (edit) || mc_global.widget.midnight_shutdown)
2518 return mc_global.widget.midnight_shutdown;
2519 break;
2520 case 1: /* No */
2521 break;
2522 case 2: /* Cancel quit */
2523 case -1: /* Esc */
2524 return FALSE;
2527 return TRUE;
2530 /* --------------------------------------------------------------------------------------------- */
2531 /** save block, returns 1 on success */
2534 edit_save_block (WEdit * edit, const char *filename, long start, long finish)
2536 int len, file;
2538 file = mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2539 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY);
2540 if (file == -1)
2541 return 0;
2543 if (edit->column_highlight)
2545 int r;
2546 r = mc_write (file, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC));
2547 if (r > 0)
2549 unsigned char *block, *p;
2550 p = block = edit_get_block (edit, start, finish, &len);
2551 while (len)
2553 r = mc_write (file, p, len);
2554 if (r < 0)
2555 break;
2556 p += r;
2557 len -= r;
2559 g_free (block);
2562 else
2564 unsigned char *buf;
2565 int i = start, end;
2566 len = finish - start;
2567 buf = g_malloc0 (TEMP_BUF_LEN);
2568 while (start != finish)
2570 end = min (finish, start + TEMP_BUF_LEN);
2571 for (; i < end; i++)
2572 buf[i - start] = edit_get_byte (edit, i);
2573 len -= mc_write (file, (char *) buf, end - start);
2574 start = end;
2576 g_free (buf);
2578 mc_close (file);
2579 if (len)
2580 return 0;
2581 return 1;
2584 /* --------------------------------------------------------------------------------------------- */
2586 void
2587 edit_paste_from_history (WEdit * edit)
2589 (void) edit;
2590 edit_error_dialog (_("Error"), _("This function is not implemented"));
2593 /* --------------------------------------------------------------------------------------------- */
2596 edit_copy_to_X_buf_cmd (WEdit * edit)
2598 long start_mark, end_mark;
2599 if (eval_marks (edit, &start_mark, &end_mark))
2600 return 0;
2601 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2603 edit_error_dialog (_("Copy to clipboard"), get_sys_error (_("Unable to save to file")));
2604 return 1;
2606 /* try use external clipboard utility */
2607 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
2609 return 0;
2612 /* --------------------------------------------------------------------------------------------- */
2615 edit_cut_to_X_buf_cmd (WEdit * edit)
2617 long start_mark, end_mark;
2618 if (eval_marks (edit, &start_mark, &end_mark))
2619 return 0;
2620 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2622 edit_error_dialog (_("Cut to clipboard"), _("Unable to save to file"));
2623 return 1;
2625 /* try use external clipboard utility */
2626 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
2628 edit_block_delete_cmd (edit);
2629 edit_mark_cmd (edit, 1);
2630 return 0;
2633 /* --------------------------------------------------------------------------------------------- */
2635 void
2636 edit_paste_from_X_buf_cmd (WEdit * edit)
2638 gchar *tmp;
2639 /* try use external clipboard utility */
2640 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", NULL);
2641 tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_CLIP_FILE);
2642 edit_insert_file (edit, tmp);
2643 g_free (tmp);
2647 /* --------------------------------------------------------------------------------------------- */
2649 * Ask user for the line and go to that line.
2650 * Negative numbers mean line from the end (i.e. -1 is the last line).
2653 void
2654 edit_goto_cmd (WEdit * edit)
2656 char *f;
2657 static long line = 0; /* line as typed, saved as default */
2658 long l;
2659 char *error;
2660 char s[32];
2662 g_snprintf (s, sizeof (s), "%ld", line);
2663 f = input_dialog (_("Goto line"), _("Enter line:"), MC_HISTORY_EDIT_GOTO_LINE, line ? s : "");
2664 if (!f)
2665 return;
2667 if (!*f)
2669 g_free (f);
2670 return;
2673 l = strtol (f, &error, 0);
2674 if (*error)
2676 g_free (f);
2677 return;
2680 line = l;
2681 if (l < 0)
2682 l = edit->total_lines + l + 2;
2683 edit_move_display (edit, l - edit->widget.lines / 2 - 1);
2684 edit_move_to_line (edit, l - 1);
2685 edit->force |= REDRAW_COMPLETELY;
2686 g_free (f);
2690 /* --------------------------------------------------------------------------------------------- */
2691 /** Return 1 on success */
2694 edit_save_block_cmd (WEdit * edit)
2696 long start_mark, end_mark;
2697 char *exp, *tmp;
2699 if (eval_marks (edit, &start_mark, &end_mark))
2700 return 1;
2702 tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_CLIP_FILE);
2703 exp =
2704 input_expand_dialog (_("Save block"), _("Enter file name:"),
2705 MC_HISTORY_EDIT_SAVE_BLOCK, tmp);
2706 g_free (tmp);
2707 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
2708 if (exp)
2710 if (!*exp)
2712 g_free (exp);
2713 return 0;
2715 else
2717 if (edit_save_block (edit, exp, start_mark, end_mark))
2719 g_free (exp);
2720 edit->force |= REDRAW_COMPLETELY;
2721 return 1;
2723 else
2725 g_free (exp);
2726 edit_error_dialog (_("Save block"), get_sys_error (_("Cannot save file")));
2730 edit->force |= REDRAW_COMPLETELY;
2731 return 0;
2735 /* --------------------------------------------------------------------------------------------- */
2736 /** returns 1 on success */
2739 edit_insert_file_cmd (WEdit * edit)
2741 gchar *tmp;
2742 char *exp;
2744 tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_CLIP_FILE);
2745 exp = input_expand_dialog (_("Insert file"), _("Enter file name:"),
2746 MC_HISTORY_EDIT_INSERT_FILE, tmp);
2747 g_free (tmp);
2748 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
2749 if (exp)
2751 if (!*exp)
2753 g_free (exp);
2754 return 0;
2756 else
2758 if (edit_insert_file (edit, exp) != 0)
2760 g_free (exp);
2761 edit->force |= REDRAW_COMPLETELY;
2762 return 1;
2764 else
2766 g_free (exp);
2767 edit_error_dialog (_("Insert file"), get_sys_error (_("Cannot insert file")));
2771 edit->force |= REDRAW_COMPLETELY;
2772 return 0;
2775 /* --------------------------------------------------------------------------------------------- */
2776 /** sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2779 edit_sort_cmd (WEdit * edit)
2781 static char *old = 0;
2782 char *exp, *tmp;
2783 long start_mark, end_mark;
2784 int e;
2786 if (eval_marks (edit, &start_mark, &end_mark))
2788 edit_error_dialog (_("Sort block"), _("You must first highlight a block of text"));
2789 return 0;
2792 tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_BLOCK_FILE);
2793 edit_save_block (edit, tmp, start_mark, end_mark);
2794 g_free (tmp);
2796 exp = input_dialog (_("Run sort"),
2797 _("Enter sort options (see manpage) separated by whitespace:"),
2798 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2800 if (!exp)
2801 return 1;
2802 g_free (old);
2803 old = exp;
2804 tmp =
2805 g_strconcat (" sort ", exp, " ", mc_config_get_cache_path (), PATH_SEP_STR EDIT_BLOCK_FILE,
2806 " > ", mc_config_get_cache_path (), PATH_SEP_STR EDIT_TEMP_FILE,
2807 (char *) NULL);
2808 e = system (tmp);
2809 g_free (tmp);
2810 if (e)
2812 if (e == -1 || e == 127)
2814 edit_error_dialog (_("Sort"), get_sys_error (_("Cannot execute sort command")));
2816 else
2818 char q[8];
2819 sprintf (q, "%d ", e);
2820 tmp = g_strdup_printf (_("Sort returned non-zero: %s"), q);
2821 edit_error_dialog (_("Sort"), tmp);
2822 g_free (tmp);
2824 return -1;
2827 edit->force |= REDRAW_COMPLETELY;
2829 if (edit_block_delete_cmd (edit))
2830 return 1;
2831 tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_TEMP_FILE);
2832 edit_insert_file (edit, tmp);
2833 g_free (tmp);
2834 return 0;
2837 /* --------------------------------------------------------------------------------------------- */
2839 * Ask user for a command, execute it and paste its output back to the
2840 * editor.
2844 edit_ext_cmd (WEdit * edit)
2846 char *exp, *tmp;
2847 int e;
2849 exp =
2850 input_dialog (_("Paste output of external command"),
2851 _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2853 if (!exp)
2854 return 1;
2856 tmp =
2857 g_strconcat (exp, " > ", mc_config_get_cache_path (), PATH_SEP_STR EDIT_TEMP_FILE,
2858 (char *) NULL);
2859 e = system (tmp);
2860 g_free (tmp);
2861 g_free (exp);
2863 if (e)
2865 edit_error_dialog (_("External command"), get_sys_error (_("Cannot execute command")));
2866 return -1;
2869 edit->force |= REDRAW_COMPLETELY;
2870 tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_TEMP_FILE);
2871 edit_insert_file (edit, tmp);
2872 g_free (tmp);
2873 return 0;
2876 /* --------------------------------------------------------------------------------------------- */
2877 /** if block is 1, a block must be highlighted and the shell command
2878 processes it. If block is 0 the shell command is a straight system
2879 command, that just produces some output which is to be inserted */
2881 void
2882 edit_block_process_cmd (WEdit * edit, int macro_number)
2884 char *fname;
2885 char *macros_fname = NULL;
2887 fname = g_strdup_printf ("%s.%i.sh", MC_EXTMACRO_FILE, macro_number);
2888 macros_fname = g_build_filename (mc_config_get_data_path (), fname, (char *) NULL);
2889 user_menu (edit, macros_fname, 0);
2890 g_free (fname);
2891 g_free (macros_fname);
2892 edit->force |= REDRAW_COMPLETELY;
2895 /* --------------------------------------------------------------------------------------------- */
2897 * prints at the cursor
2898 * @returns the number of chars printed
2902 edit_print_string (WEdit * e, const char *s)
2904 size_t i = 0;
2905 while (s[i] != '\0')
2906 edit_execute_cmd (e, CK_InsertChar, (unsigned char) s[i++]);
2907 e->force |= REDRAW_COMPLETELY;
2908 edit_update_screen (e);
2909 return i;
2912 /* --------------------------------------------------------------------------------------------- */
2914 void
2915 edit_mail_dialog (WEdit * edit)
2917 char *tmail_to;
2918 char *tmail_subject;
2919 char *tmail_cc;
2921 static char *mail_cc_last = 0;
2922 static char *mail_subject_last = 0;
2923 static char *mail_to_last = 0;
2925 QuickWidget quick_widgets[] = {
2926 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2927 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2928 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2929 /* 3 */ QUICK_LABEL (3, 50, 7, MAIL_DLG_HEIGHT, N_("Copies to")),
2930 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2",
2931 &tmail_subject),
2932 /* 5 */ QUICK_LABEL (3, 50, 5, MAIL_DLG_HEIGHT, N_("Subject")),
2933 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2934 /* 7 */ QUICK_LABEL (3, 50, 3, MAIL_DLG_HEIGHT, N_("To")),
2935 /* 8 */ QUICK_LABEL (3, 50, 2, MAIL_DLG_HEIGHT, N_("mail -s <subject> -c <cc> <to>")),
2936 QUICK_END
2939 QuickDialog Quick_input = {
2940 50, MAIL_DLG_HEIGHT, -1, -1, N_("Mail"),
2941 "[Input Line Keys]", quick_widgets, NULL, FALSE
2944 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2945 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2946 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2948 if (quick_dialog (&Quick_input) != B_CANCEL)
2950 g_free (mail_cc_last);
2951 g_free (mail_subject_last);
2952 g_free (mail_to_last);
2953 mail_cc_last = tmail_cc;
2954 mail_subject_last = tmail_subject;
2955 mail_to_last = tmail_to;
2956 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2961 /*******************/
2962 /* Word Completion */
2963 /*******************/
2965 /* --------------------------------------------------------------------------------------------- */
2967 * Complete current word using regular expression search
2968 * backwards beginning at the current cursor position.
2971 void
2972 edit_complete_word_cmd (WEdit * edit)
2974 gsize i, max_len, word_len = 0, num_compl = 0;
2975 long word_start = 0;
2976 unsigned char *bufpos;
2977 char *match_expr;
2978 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2980 /* search start of word to be completed */
2981 if (!edit_find_word_start (edit, &word_start, &word_len))
2982 return;
2984 /* prepare match expression */
2985 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
2987 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2988 match_expr =
2989 g_strdup_printf
2990 ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+",
2991 (int) word_len, bufpos);
2993 /* collect the possible completions */
2994 /* start search from begin to end of file */
2995 max_len =
2996 edit_collect_completions (edit, word_start, word_len, match_expr,
2997 (struct selection *) &compl, &num_compl);
2999 if (num_compl > 0)
3001 /* insert completed word if there is only one match */
3002 if (num_compl == 1)
3004 for (i = word_len; i < compl[0].len; i++)
3005 edit_insert (edit, *(compl[0].text + i));
3007 /* more than one possible completion => ask the user */
3008 else
3010 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
3011 /* !!! pressed again the selection dialog pops up, but that !!! */
3012 /* !!! seems to require a further internal state !!! */
3013 /*tty_beep (); */
3015 /* let the user select the preferred completion */
3016 editcmd_dialog_completion_show (edit, max_len, word_len,
3017 (struct selection *) &compl, num_compl);
3021 g_free (match_expr);
3022 /* release memory before return */
3023 for (i = 0; i < num_compl; i++)
3024 g_free (compl[i].text);
3027 /* --------------------------------------------------------------------------------------------- */
3029 void
3030 edit_select_codepage_cmd (WEdit * edit)
3032 #ifdef HAVE_CHARSET
3033 if (do_select_codepage ())
3034 edit_set_codeset (edit);
3036 edit->force = REDRAW_COMPLETELY;
3037 edit_refresh_cmd (edit);
3038 #else
3039 (void) edit;
3040 #endif
3043 /* --------------------------------------------------------------------------------------------- */
3045 void
3046 edit_insert_literal_cmd (WEdit * edit)
3048 int char_for_insertion = editcmd_dialog_raw_key_query (_("Insert literal"),
3049 _("Press any key:"), 0);
3050 edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
3053 /* --------------------------------------------------------------------------------------------- */
3055 void
3056 edit_begin_end_macro_cmd (WEdit * edit)
3058 /* edit is a pointer to the widget */
3059 if (edit != NULL)
3061 unsigned long command = macro_index < 0 ? CK_MacroStartRecord : CK_MacroStopRecord;
3062 edit_execute_key_command (edit, command, -1);
3066 /* --------------------------------------------------------------------------------------------- */
3068 void
3069 edit_begin_end_repeat_cmd (WEdit * edit)
3071 /* edit is a pointer to the widget */
3072 if (edit != NULL)
3074 unsigned long command = macro_index < 0 ? CK_RepeatStartRecord : CK_RepeatStopRecord;
3075 edit_execute_key_command (edit, command, -1);
3079 /* --------------------------------------------------------------------------------------------- */
3082 edit_load_forward_cmd (WEdit * edit)
3084 if (edit->modified)
3086 if (edit_query_dialog2
3087 (_("Warning"),
3088 _("Current text was modified without a file save\n"
3089 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")))
3091 edit->force |= REDRAW_COMPLETELY;
3092 return 0;
3095 if (edit_stack_iterator + 1 < MAX_HISTORY_MOVETO)
3097 if (edit_history_moveto[edit_stack_iterator + 1].line < 1)
3099 return 1;
3101 edit_stack_iterator++;
3102 if (edit_history_moveto[edit_stack_iterator].filename)
3104 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
3105 edit_history_moveto[edit_stack_iterator].line);
3106 return 0;
3108 else
3110 return 1;
3113 else
3115 return 1;
3119 /* --------------------------------------------------------------------------------------------- */
3122 edit_load_back_cmd (WEdit * edit)
3124 if (edit->modified)
3126 if (edit_query_dialog2
3127 (_("Warning"),
3128 _("Current text was modified without a file save\n"
3129 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")))
3131 edit->force |= REDRAW_COMPLETELY;
3132 return 0;
3135 if (edit_stack_iterator > 0)
3137 edit_stack_iterator--;
3138 if (edit_history_moveto[edit_stack_iterator].filename)
3140 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
3141 edit_history_moveto[edit_stack_iterator].line);
3142 return 0;
3144 else
3146 return 1;
3149 else
3151 return 1;
3155 /* --------------------------------------------------------------------------------------------- */
3157 void
3158 edit_get_match_keyword_cmd (WEdit * edit)
3160 gsize word_len = 0, max_len = 0;
3161 int num_def = 0;
3162 int i;
3163 long word_start = 0;
3164 unsigned char *bufpos;
3165 char *match_expr;
3166 char *path = NULL;
3167 char *ptr = NULL;
3168 char *tagfile = NULL;
3170 etags_hash_t def_hash[MAX_DEFINITIONS];
3172 for (i = 0; i < MAX_DEFINITIONS; i++)
3174 def_hash[i].filename = NULL;
3177 /* search start of word to be completed */
3178 if (!edit_find_word_start (edit, &word_start, &word_len))
3179 return;
3181 /* prepare match expression */
3182 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
3183 match_expr = g_strdup_printf ("%.*s", (int) word_len, bufpos);
3185 ptr = g_get_current_dir ();
3186 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
3187 g_free (ptr);
3189 /* Recursive search file 'TAGS' in parent dirs */
3192 ptr = g_path_get_dirname (path);
3193 g_free (path);
3194 path = ptr;
3195 g_free (tagfile);
3196 tagfile = mc_build_filename (path, TAGS_NAME, (char *) NULL);
3197 if (exist_file (tagfile))
3198 break;
3200 while (strcmp (path, G_DIR_SEPARATOR_S) != 0);
3202 if (tagfile)
3204 num_def =
3205 etags_set_definition_hash (tagfile, path, match_expr, (etags_hash_t *) & def_hash);
3206 g_free (tagfile);
3208 g_free (path);
3210 max_len = MAX_WIDTH_DEF_DIALOG;
3211 word_len = 0;
3212 if (num_def > 0)
3214 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
3215 (etags_hash_t *) & def_hash, num_def);
3217 g_free (match_expr);
3220 /* --------------------------------------------------------------------------------------------- */
3222 void
3223 edit_move_block_to_right (WEdit * edit)
3225 long start_mark, end_mark;
3226 long cur_bol, start_bol;
3228 if (eval_marks (edit, &start_mark, &end_mark))
3229 return;
3231 start_bol = edit_bol (edit, start_mark);
3232 cur_bol = edit_bol (edit, end_mark - 1);
3235 edit_cursor_move (edit, cur_bol - edit->curs1);
3236 if (option_fill_tabs_with_spaces)
3238 if (option_fake_half_tabs)
3240 insert_spaces_tab (edit, 1);
3242 else
3244 insert_spaces_tab (edit, 0);
3247 else
3249 edit_insert (edit, '\t');
3251 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
3252 if (cur_bol == 0)
3254 break;
3256 cur_bol = edit_bol (edit, cur_bol - 1);
3258 while (cur_bol >= start_bol);
3259 edit->force |= REDRAW_PAGE;
3262 /* --------------------------------------------------------------------------------------------- */
3264 void
3265 edit_move_block_to_left (WEdit * edit)
3267 long start_mark, end_mark;
3268 long cur_bol, start_bol;
3269 int i, del_tab_width;
3270 int next_char;
3272 if (eval_marks (edit, &start_mark, &end_mark))
3273 return;
3275 start_bol = edit_bol (edit, start_mark);
3276 cur_bol = edit_bol (edit, end_mark - 1);
3279 edit_cursor_move (edit, cur_bol - edit->curs1);
3280 if (option_fake_half_tabs)
3282 del_tab_width = HALF_TAB_SIZE;
3284 else
3286 del_tab_width = option_tab_spacing;
3288 next_char = edit_get_byte (edit, edit->curs1);
3289 if (next_char == '\t')
3291 edit_delete (edit, 1);
3293 else if (next_char == ' ')
3295 for (i = 1; i <= del_tab_width; i++)
3297 if (next_char == ' ')
3299 edit_delete (edit, 1);
3301 next_char = edit_get_byte (edit, edit->curs1);
3304 if (cur_bol == 0)
3306 break;
3308 cur_bol = edit_bol (edit, cur_bol - 1);
3310 while (cur_bol >= start_bol);
3311 edit->force |= REDRAW_PAGE;
3314 /* --------------------------------------------------------------------------------------------- */