Ticket #30 (use external clipboard utility)
[midnight-commander.git] / src / editor / editcmd.c
blob21cabb601c268a43465e1aed9d75741f7efc3cc1
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/vfs/mc-vfs/vfs.h"
56 #include "src/history.h"
57 #include "src/widget.h" /* listbox_new() */
58 #include "src/layout.h" /* clr_scr() */
59 #include "src/main.h" /* mc_home */
60 #include "src/help.h" /* interactive_display() */
61 #include "src/wtools.h" /* message() */
62 #include "src/charsets.h"
63 #include "src/selcodepage.h"
64 #include "src/cmddef.h"
65 #include "src/clipboard.h" /* copy_file_to_ext_clip, paste_to_file_from_ext_clip */
67 #include "src/editor/edit-impl.h"
68 #include "src/editor/editlock.h"
69 #include "src/editor/edit-widget.h"
70 #include "src/editor/editcmd_dialogs.h"
71 #include "src/editor/etags.h"
73 /* globals: */
75 /* search and replace: */
76 int search_create_bookmark = 0;
77 /* static int search_in_all_charsets = 0; */
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 static void
86 edit_search_cmd_search_create_bookmark (WEdit * edit)
88 int found = 0, books = 0;
89 long l = 0, l_last = -1;
90 long q = 0;
91 gsize len = 0;
93 search_create_bookmark = 0;
94 book_mark_flush (edit, -1);
96 for (;;)
98 if (!mc_search_run (edit->search, (void *) edit, q, edit->last_byte, &len))
99 break;
100 if (found == 0)
101 edit->search_start = edit->search->normal_offset;
102 found++;
103 l += edit_count_lines (edit, q, edit->search->normal_offset);
104 if (l != l_last)
106 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
107 books++;
109 l_last = l;
110 q = edit->search->normal_offset + 1;
113 if (found == 0)
115 edit_error_dialog (_("Search"), _("Search string not found"));
117 else
119 edit_cursor_move (edit, edit->search_start - edit->curs1);
120 edit_scroll_screen_over_cursor (edit);
124 static int
125 edit_search_cmd_callback (const void *user_data, gsize char_offset)
127 return edit_get_byte ((WEdit *) user_data, (long) char_offset);
130 void
131 edit_help_cmd (WEdit * edit)
133 interactive_display (NULL, "[Internal File Editor]");
134 edit->force |= REDRAW_COMPLETELY;
137 void
138 edit_refresh_cmd (WEdit * edit)
140 #ifdef HAVE_SLANG
141 int color;
143 edit_get_syntax_color (edit, -1, &color);
144 tty_touch_screen ();
145 mc_refresh ();
146 #else
147 (void) edit;
149 clr_scr ();
150 repaint_screen ();
151 #endif /* !HAVE_SLANG */
152 tty_keypad (TRUE);
155 /* If 0 (quick save) then a) create/truncate <filename> file,
156 b) save to <filename>;
157 if 1 (safe save) then a) save to <tempnam>,
158 b) rename <tempnam> to <filename>;
159 if 2 (do backups) then a) save to <tempnam>,
160 b) rename <filename> to <filename.backup_ext>,
161 c) rename <tempnam> to <filename>. */
163 /* returns 0 on error, -1 on abort */
164 static int
165 edit_save_file (WEdit * edit, const char *filename)
167 char *p;
168 gchar *tmp;
169 long filelen = 0;
170 char *savename = 0;
171 gchar *real_filename;
172 int this_save_mode, fd = -1;
174 if (!filename)
175 return 0;
176 if (!*filename)
177 return 0;
179 if (*filename != PATH_SEP && edit->dir)
181 real_filename = concat_dir_and_file (edit->dir, filename);
183 else
185 real_filename = g_strdup (filename);
188 this_save_mode = option_save_mode;
189 if (this_save_mode != EDIT_QUICK_SAVE)
191 if (!vfs_file_is_local (real_filename) ||
192 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1)
195 * The file does not exists yet, so no safe save or
196 * backup are necessary.
198 this_save_mode = EDIT_QUICK_SAVE;
200 if (fd != -1)
201 mc_close (fd);
204 if (this_save_mode == EDIT_QUICK_SAVE && !edit->skip_detach_prompt)
206 int rv;
207 struct stat sb;
209 rv = mc_stat (real_filename, &sb);
210 if (rv == 0 && sb.st_nlink > 1)
212 rv = edit_query_dialog3 (_("Warning"),
213 _("File has hard-links. Detach before saving?"),
214 _("&Yes"), _("&No"), _("&Cancel"));
215 switch (rv)
217 case 0:
218 this_save_mode = EDIT_SAFE_SAVE;
219 /* fallthrough */
220 case 1:
221 edit->skip_detach_prompt = 1;
222 break;
223 default:
224 g_free (real_filename);
225 return -1;
229 /* Prevent overwriting changes from other editor sessions. */
230 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime)
233 /* The default action is "Cancel". */
234 query_set_sel (1);
236 rv = edit_query_dialog2 (_("Warning"),
237 _("The file has been modified in the meantime. Save anyway?"),
238 _("&Yes"), _("&Cancel"));
239 if (rv != 0)
241 g_free (real_filename);
242 return -1;
247 if (this_save_mode != EDIT_QUICK_SAVE)
249 char *savedir, *saveprefix;
250 const char *slashpos;
251 slashpos = strrchr (real_filename, PATH_SEP);
252 if (slashpos)
254 savedir = g_strdup (real_filename);
255 savedir[slashpos - real_filename + 1] = '\0';
257 else
258 savedir = g_strdup (".");
259 saveprefix = concat_dir_and_file (savedir, "cooledit");
260 g_free (savedir);
261 fd = mc_mkstemps (&savename, saveprefix, NULL);
262 g_free (saveprefix);
263 if (!savename)
265 g_free (real_filename);
266 return 0;
268 /* FIXME:
269 * Close for now because mc_mkstemps use pure open system call
270 * to create temporary file and it needs to be reopened by
271 * VFS-aware mc_open().
273 close (fd);
275 else
276 savename = g_strdup (real_filename);
278 int ret;
279 ret = mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
280 ret = mc_chmod (savename, edit->stat1.st_mode);
283 fd = mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode);
284 if (fd == -1)
285 goto error_save;
287 /* pipe save */
288 p = edit_get_write_filter (savename, real_filename);
289 if (p != NULL)
291 FILE *file;
293 mc_close (fd);
294 file = (FILE *) popen (p, "w");
296 if (file)
298 filelen = edit_write_stream (edit, file);
299 #if 1
300 pclose (file);
301 #else
302 if (pclose (file) != 0)
304 tmp = g_strdup_printf (_("Error writing to pipe: %s"), p);
305 edit_error_dialog (_("Error"), tmp);
306 g_free (tmp);
307 g_free (p);
308 goto error_save;
310 #endif
312 else
314 tmp = g_strdup_printf (_("Cannot open pipe for writing: %s"), p);
315 edit_error_dialog (_("Error"), get_sys_error (tmp));
316 g_free (p);
317 g_free (tmp);
318 goto error_save;
320 g_free (p);
322 else if (edit->lb == LB_ASIS)
323 { /* do not change line breaks */
324 long buf;
325 buf = 0;
326 filelen = edit->last_byte;
327 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1)
329 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE)
331 mc_close (fd);
332 goto error_save;
334 buf++;
336 if (mc_write
337 (fd, (char *) edit->buffers1[buf],
338 edit->curs1 & M_EDIT_BUF_SIZE) != (edit->curs1 & M_EDIT_BUF_SIZE))
340 filelen = -1;
342 else if (edit->curs2)
344 edit->curs2--;
345 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
346 if (mc_write
347 (fd,
348 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
349 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
350 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) != 1 + (edit->curs2 & M_EDIT_BUF_SIZE))
352 filelen = -1;
354 else
356 while (--buf >= 0)
358 if (mc_write (fd, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) != EDIT_BUF_SIZE)
360 filelen = -1;
361 break;
365 edit->curs2++;
367 if (mc_close (fd))
368 goto error_save;
370 /* Update the file information, especially the mtime. */
371 if (mc_stat (savename, &edit->stat1) == -1)
372 goto error_save;
374 else
375 { /* change line breaks */
376 FILE *file;
378 mc_close (fd);
380 file = (FILE *) fopen (savename, "w");
382 if (file)
384 filelen = edit_write_stream (edit, file);
385 fclose (file);
387 else
389 char *msg;
391 msg = g_strdup_printf (_("Cannot open file for writing: %s"), savename);
392 edit_error_dialog (_("Error"), msg);
393 g_free (msg);
394 goto error_save;
398 if (filelen != edit->last_byte)
399 goto error_save;
401 if (this_save_mode == EDIT_DO_BACKUP)
403 assert (option_backup_ext != NULL);
404 tmp = g_strconcat (real_filename, option_backup_ext, (char *) NULL);
405 if (mc_rename (real_filename, tmp) == -1)
407 g_free (tmp);
408 goto error_save;
412 if (this_save_mode != EDIT_QUICK_SAVE)
413 if (mc_rename (savename, real_filename) == -1)
414 goto error_save;
415 g_free (savename);
416 g_free (real_filename);
417 return 1;
418 error_save:
419 /* FIXME: Is this safe ?
420 * if (this_save_mode != EDIT_QUICK_SAVE)
421 * mc_unlink (savename);
423 g_free (real_filename);
424 g_free (savename);
425 return 0;
428 void
429 menu_save_mode_cmd (void)
431 /* diaog sizes */
432 const int DLG_X = 38;
433 const int DLG_Y = 13;
435 char *str_result;
437 const char *str[] = {
438 N_("&Quick save"),
439 N_("&Safe save"),
440 N_("&Do backups with following extension:")
443 QuickWidget widgets[] = {
444 /* 0 */
445 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
446 /* 1 */
447 QUICK_BUTTON (6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
448 /* 2 */
449 QUICK_CHECKBOX (4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
450 /* 3 */
451 QUICK_INPUT (8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
452 /* 4 */
453 QUICK_RADIO (4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
454 QUICK_END
457 QuickDialog dialog = {
458 DLG_X, DLG_Y, -1, -1, N_("Edit Save Mode"),
459 "[Edit Save Mode]", widgets, FALSE
462 size_t i;
463 size_t maxlen = 0;
464 size_t w0, w1, b_len, w3;
466 assert (option_backup_ext != NULL);
468 /* OK/Cancel buttons */
469 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
470 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
471 b_len = w0 + w1 + 3;
473 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
475 w3 = 0;
476 for (i = 0; i < 3; i++)
478 #ifdef ENABLE_NLS
479 str[i] = _(str[i]);
480 #endif
481 w3 = max (w3, (size_t) str_term_width1 (str[i]));
484 maxlen = max (maxlen, w3 + 4);
486 dialog.xlen = min ((size_t) COLS, maxlen + 8);
488 widgets[3].u.input.len = w3;
489 widgets[1].relative_x = (dialog.xlen - b_len) / 2;
490 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
492 for (i = 0; i < sizeof (widgets) / sizeof (widgets[0]); i++)
493 widgets[i].x_divisions = dialog.xlen;
495 if (quick_dialog (&dialog) != B_CANCEL)
497 g_free (option_backup_ext);
498 option_backup_ext = str_result;
502 void
503 edit_set_filename (WEdit * edit, const char *f)
505 g_free (edit->filename);
506 if (!f)
507 f = "";
508 edit->filename = g_strdup (f);
509 if (edit->dir == NULL && *f != PATH_SEP)
510 #ifdef ENABLE_VFS
511 edit->dir = g_strdup (vfs_get_current_dir ());
512 #else /* ENABLE_VFS */
513 edit->dir = g_get_current_dir ();
514 #endif /* ENABLE_VFS */
517 static gboolean
518 edit_check_newline (WEdit * edit)
520 return !(option_check_nl_at_eof && edit->last_byte > 0
521 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
522 && edit_query_dialog2 (_("Warning"),
523 _("The file you are saving is not finished with a newline"),
524 _("C&ontinue"), _("&Cancel")));
527 static char *
528 edit_get_save_file_as (WEdit * edit)
530 #define DLG_WIDTH 64
531 #define DLG_HEIGHT 14
533 static LineBreaks cur_lb = LB_ASIS;
535 char *filename = edit->filename;
537 const char *lb_names[LB_NAMES] = {
538 N_("&Do not change"),
539 N_("&Unix format (LF)"),
540 N_("&Windows/DOS format (CR LF)"),
541 N_("&Macintosh format (CR)")
544 QuickWidget quick_widgets[] = {
545 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
546 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
547 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
548 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
549 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0,
550 "save-as", &filename),
551 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_("Enter file name:")),
552 QUICK_END
555 QuickDialog Quick_options = {
556 DLG_WIDTH, DLG_HEIGHT, -1, -1,
557 N_("Save As"), "[Save File As]",
558 quick_widgets, FALSE
561 if (quick_dialog (&Quick_options) != B_CANCEL)
563 edit->lb = cur_lb;
564 return filename;
567 return NULL;
569 #undef DLG_WIDTH
570 #undef DLG_HEIGHT
573 /* Here we want to warn the users of overwriting an existing file,
574 but only if they have made a change to the filename */
575 /* returns 1 on success */
577 edit_save_as_cmd (WEdit * edit)
579 /* This heads the 'Save As' dialog box */
580 char *exp;
581 int save_lock = 0;
582 int different_filename = 0;
584 if (!edit_check_newline (edit))
585 return 0;
587 exp = edit_get_save_file_as (edit);
588 edit_push_action (edit, KEY_PRESS + edit->start_display);
590 if (exp)
592 if (!*exp)
594 g_free (exp);
595 edit->force |= REDRAW_COMPLETELY;
596 return 0;
598 else
600 int rv;
601 if (strcmp (edit->filename, exp))
603 int file;
604 different_filename = 1;
605 file = mc_open (exp, O_RDONLY | O_BINARY);
606 if (file != -1)
608 /* the file exists */
609 mc_close (file);
610 /* Overwrite the current file or cancel the operation */
611 if (edit_query_dialog2
612 (_("Warning"),
613 _("A file already exists with this name"),
614 _("&Overwrite"), _("&Cancel")))
616 edit->force |= REDRAW_COMPLETELY;
617 g_free (exp);
618 return 0;
621 else
623 edit->stat1.st_mode |= S_IWUSR;
625 save_lock = edit_lock_file (exp);
627 else
629 /* filenames equal, check if already locked */
630 if (!edit->locked && !edit->delete_file)
631 save_lock = edit_lock_file (exp);
634 if (different_filename)
637 * Allow user to write into saved (under another name) file
638 * even if original file had r/o user permissions.
640 edit->stat1.st_mode |= S_IWRITE;
643 rv = edit_save_file (edit, exp);
644 switch (rv)
646 case 1:
647 /* Succesful, so unlock both files */
648 if (different_filename)
650 if (save_lock)
651 edit_unlock_file (exp);
652 if (edit->locked)
653 edit->locked = edit_unlock_file (edit->filename);
655 else
657 if (edit->locked || save_lock)
658 edit->locked = edit_unlock_file (edit->filename);
661 edit_set_filename (edit, exp);
662 if (edit->lb != LB_ASIS)
663 edit_reload (edit, exp);
664 g_free (exp);
665 edit->modified = 0;
666 edit->delete_file = 0;
667 if (different_filename)
668 edit_load_syntax (edit, NULL, edit->syntax_type);
669 edit->force |= REDRAW_COMPLETELY;
670 return 1;
671 default:
672 edit_error_dialog (_("Save as"), get_sys_error (_("Cannot save file")));
673 /* fallthrough */
674 case -1:
675 /* Failed, so maintain modify (not save) lock */
676 if (save_lock)
677 edit_unlock_file (exp);
678 g_free (exp);
679 edit->force |= REDRAW_COMPLETELY;
680 return 0;
684 edit->force |= REDRAW_COMPLETELY;
685 return 0;
688 /* {{{ Macro stuff starts here */
690 /* creates a macro file if it doesn't exist */
691 static FILE *
692 edit_open_macro_file (const char *r)
694 gchar *filename;
695 FILE *fd;
696 int file;
697 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
698 file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
699 if (file == -1)
701 g_free (filename);
702 return 0;
704 close (file);
705 fd = fopen (filename, r);
706 g_free (filename);
707 return fd;
710 #define MAX_MACROS 1024
711 static int saved_macro[MAX_MACROS + 1];
712 static int saved_macros_loaded = 0;
715 This is just to stop the macro file be loaded over and over for keys
716 that aren't defined to anything. On slow systems this could be annoying.
718 static int
719 macro_exists (int k)
721 int i;
722 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
723 if (saved_macro[i] == k)
724 return i;
725 return -1;
728 /* returns 1 on error */
729 static int
730 edit_delete_macro (WEdit * edit, int k)
732 gchar *tmp, *tmp2;
733 struct macro macro[MAX_MACRO_LENGTH];
734 FILE *f, *g;
735 int s, i, n, j = 0;
737 (void) edit;
739 if (saved_macros_loaded)
741 j = macro_exists (k);
742 if (j < 0)
743 return 0;
745 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
746 g = fopen (tmp, "w");
747 g_free (tmp);
748 if (!g)
750 edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot open temp file")));
751 return 1;
753 f = edit_open_macro_file ("r");
754 if (!f)
756 edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot open macro file")));
757 fclose (g);
758 return 1;
760 for (;;)
762 n = fscanf (f, ("key '%d 0': "), &s);
763 if (!n || n == EOF)
764 break;
765 n = 0;
766 while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
767 n++;
769 int ret;
770 ret = fscanf (f, ";\n");
772 if (s != k)
774 fprintf (g, ("key '%d 0': "), s);
775 for (i = 0; i < n; i++)
776 fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
777 fprintf (g, ";\n");
780 fclose (f);
781 fclose (g);
782 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
783 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
784 if (rename (tmp, tmp2) == -1)
786 edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot overwrite macro file")));
787 g_free (tmp);
788 g_free (tmp2);
789 return 1;
791 g_free (tmp);
792 g_free (tmp2);
794 if (saved_macros_loaded)
795 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
796 return 0;
799 /* returns 0 on error */
801 edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
803 FILE *f;
804 int s, i;
806 edit_push_action (edit, KEY_PRESS + edit->start_display);
807 s = editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), 1);
808 edit->force |= REDRAW_COMPLETELY;
809 if (s)
811 if (edit_delete_macro (edit, s))
812 return 0;
813 f = edit_open_macro_file ("a+");
814 if (f)
816 fprintf (f, ("key '%d 0': "), s);
817 for (i = 0; i < n; i++)
818 fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
819 fprintf (f, ";\n");
820 fclose (f);
821 if (saved_macros_loaded)
823 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
824 saved_macro[i] = s;
826 return 1;
828 else
829 edit_error_dialog (_("Save macro"), get_sys_error (_("Cannot open macro file")));
831 return 0;
834 void
835 edit_delete_macro_cmd (WEdit * edit)
837 int command;
839 command = editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), 1);
841 if (command != 0)
842 edit_delete_macro (edit, command);
845 /* return 0 on error */
847 edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
849 FILE *f;
850 int s, i = 0, found = 0;
852 (void) edit;
854 if (saved_macros_loaded)
855 if (macro_exists (k) < 0)
856 return 0;
858 f = edit_open_macro_file ("r");
859 if (f != NULL)
861 struct macro dummy;
864 int u;
865 u = fscanf (f, ("key '%d 0': "), &s);
866 if (!u || u == EOF)
867 break;
868 if (!saved_macros_loaded)
869 saved_macro[i++] = s;
870 if (!found)
872 *n = 0;
873 while (*n < MAX_MACRO_LENGTH
874 && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
875 (*n)++;
877 else
879 while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
882 int ret;
883 ret = fscanf (f, ";\n");
885 if (s == k)
886 found = 1;
888 while (!found || !saved_macros_loaded);
889 if (!saved_macros_loaded)
891 saved_macro[i] = 0;
892 saved_macros_loaded = 1;
894 fclose (f);
895 return found;
897 else
898 edit_error_dialog (_("Load macro"), get_sys_error (_("Cannot open macro file")));
899 return 0;
902 /* }}} Macro stuff starts here */
904 /* returns 1 on success */
906 edit_save_confirm_cmd (WEdit * edit)
908 gchar *f = NULL;
910 if (!edit_check_newline (edit))
911 return 0;
913 if (edit_confirm_save)
915 f = g_strdup_printf (_("Confirm save file: \"%s\""), edit->filename);
916 if (edit_query_dialog2 (_("Save file"), f, _("&Save"), _("&Cancel")))
918 g_free (f);
919 return 0;
921 g_free (f);
923 return edit_save_cmd (edit);
927 /* returns 1 on success */
928 static int
929 edit_save_cmd (WEdit * edit)
931 int res, save_lock = 0;
933 if (!edit->locked && !edit->delete_file)
934 save_lock = edit_lock_file (edit->filename);
935 res = edit_save_file (edit, edit->filename);
937 /* Maintain modify (not save) lock on failure */
938 if ((res > 0 && edit->locked) || save_lock)
939 edit->locked = edit_unlock_file (edit->filename);
941 /* On failure try 'save as', it does locking on its own */
942 if (!res)
943 return edit_save_as_cmd (edit);
944 edit->force |= REDRAW_COMPLETELY;
945 if (res > 0)
947 edit->delete_file = 0;
948 edit->modified = 0;
951 return 1;
955 /* returns 1 on success */
957 edit_new_cmd (WEdit * edit)
959 if (edit->modified)
961 if (edit_query_dialog2
962 (_("Warning"),
964 ("Current text was modified without a file save.\nContinue discards these changes"),
965 _("C&ontinue"), _("&Cancel")))
967 edit->force |= REDRAW_COMPLETELY;
968 return 0;
971 edit->force |= REDRAW_COMPLETELY;
973 return edit_renew (edit); /* if this gives an error, something has really screwed up */
976 /* returns 1 on error */
977 static int
978 edit_load_file_from_filename (WEdit * edit, char *exp)
980 int prev_locked = edit->locked;
981 char *prev_filename = g_strdup (edit->filename);
983 if (!edit_reload (edit, exp))
985 g_free (prev_filename);
986 return 1;
989 if (prev_locked)
990 edit_unlock_file (prev_filename);
991 g_free (prev_filename);
992 return 0;
995 static void
996 edit_load_syntax_file (WEdit * edit)
998 char *extdir;
999 int dir = 0;
1001 if (geteuid () == 0)
1003 dir = query_dialog (_("Syntax file edit"),
1004 _("Which syntax file you want to edit?"), D_NORMAL, 2,
1005 _("&User"), _("&System Wide"));
1008 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
1009 if (!exist_file (extdir))
1011 g_free (extdir);
1012 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
1015 if (dir == 0)
1017 char *buffer;
1019 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
1020 check_for_default (extdir, buffer);
1021 edit_load_file_from_filename (edit, buffer);
1022 g_free (buffer);
1024 else if (dir == 1)
1025 edit_load_file_from_filename (edit, extdir);
1027 g_free (extdir);
1030 static void
1031 edit_load_menu_file (WEdit * edit)
1033 char *buffer;
1034 char *menufile;
1035 int dir = 0;
1037 dir = query_dialog (_("Menu edit"),
1038 _("Which menu file do you want to edit?"), D_NORMAL,
1039 geteuid () != 0 ? 2 : 3, _("&Local"), _("&User"), _("&System Wide"));
1041 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
1043 if (!exist_file (menufile))
1045 g_free (menufile);
1046 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
1049 switch (dir)
1051 case 0:
1052 buffer = g_strdup (EDIT_LOCAL_MENU);
1053 check_for_default (menufile, buffer);
1054 chmod (buffer, 0600);
1055 break;
1057 case 1:
1058 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
1059 check_for_default (menufile, buffer);
1060 break;
1062 case 2:
1063 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
1064 if (!exist_file (buffer))
1066 g_free (buffer);
1067 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
1069 break;
1071 default:
1072 g_free (menufile);
1073 return;
1076 edit_load_file_from_filename (edit, buffer);
1078 g_free (buffer);
1079 g_free (menufile);
1083 edit_load_cmd (WEdit * edit, edit_current_file_t what)
1085 char *exp;
1087 if (edit->modified
1088 && (edit_query_dialog2
1089 (_("Warning"),
1090 _("Current text was modified without a file save.\n"
1091 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")) == 1))
1093 edit->force |= REDRAW_COMPLETELY;
1094 return 0;
1097 switch (what)
1099 case EDIT_FILE_COMMON:
1100 exp = input_expand_dialog (_("Load"), _("Enter file name:"),
1101 MC_HISTORY_EDIT_LOAD, edit->filename);
1103 if (exp)
1105 if (*exp)
1106 edit_load_file_from_filename (edit, exp);
1107 g_free (exp);
1109 break;
1111 case EDIT_FILE_SYNTAX:
1112 edit_load_syntax_file (edit);
1113 break;
1115 case EDIT_FILE_MENU:
1116 edit_load_menu_file (edit);
1117 break;
1119 default:
1120 break;
1123 edit->force |= REDRAW_COMPLETELY;
1124 return 0;
1128 if mark2 is -1 then marking is from mark1 to the cursor.
1129 Otherwise its between the markers. This handles this.
1130 Returns 1 if no text is marked.
1133 eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1135 if (edit->mark1 != edit->mark2)
1137 long start_bol, start_eol;
1138 long end_bol, end_eol;
1139 long col1, col2;
1140 long diff1, diff2;
1141 if (edit->mark2 >= 0)
1143 *start_mark = min (edit->mark1, edit->mark2);
1144 *end_mark = max (edit->mark1, edit->mark2);
1146 else
1148 *start_mark = min (edit->mark1, edit->curs1);
1149 *end_mark = max (edit->mark1, edit->curs1);
1150 edit->column2 = edit->curs_col + edit->over_col;
1152 if (column_highlighting
1153 && (((edit->mark1 > edit->curs1) && (edit->column1 < edit->column2))
1154 || ((edit->mark1 < edit->curs1) && (edit->column1 > edit->column2))))
1157 start_bol = edit_bol (edit, *start_mark);
1158 start_eol = edit_eol (edit, start_bol - 1) + 1;
1159 end_bol = edit_bol (edit, *end_mark);
1160 end_eol = edit_eol (edit, *end_mark);
1161 col1 = min (edit->column1, edit->column2);
1162 col2 = max (edit->column1, edit->column2);
1164 diff1 =
1165 edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol,
1166 col1, 0);
1167 diff2 =
1168 edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol,
1169 col1, 0);
1171 *start_mark -= diff1;
1172 *end_mark += diff2;
1173 *start_mark = max (*start_mark, start_eol);
1174 *end_mark = min (*end_mark, end_eol);
1176 return 0;
1178 else
1180 *start_mark = *end_mark = 0;
1181 edit->column2 = edit->column1 = 0;
1182 return 1;
1186 #define space_width 1
1188 void
1189 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1191 long cursor;
1192 int i, col;
1193 cursor = edit->curs1;
1194 col = edit_get_col (edit);
1195 for (i = 0; i < size; i++)
1197 if (data[i] == '\n')
1198 { /* fill in and move to next line */
1199 int l;
1200 long p;
1201 if (edit_get_byte (edit, edit->curs1) != '\n')
1203 l = width - (edit_get_col (edit) - col);
1204 while (l > 0)
1206 edit_insert (edit, ' ');
1207 l -= space_width;
1210 for (p = edit->curs1;; p++)
1212 if (p == edit->last_byte)
1214 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1215 edit_insert_ahead (edit, '\n');
1216 p++;
1217 break;
1219 if (edit_get_byte (edit, p) == '\n')
1221 p++;
1222 break;
1225 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1226 l = col - edit_get_col (edit);
1227 while (l >= space_width)
1229 edit_insert (edit, ' ');
1230 l -= space_width;
1232 continue;
1234 edit_insert (edit, data[i]);
1236 edit_cursor_move (edit, cursor - edit->curs1);
1239 #define TEMP_BUF_LEN 1024
1242 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1244 long cursor;
1245 int i, col;
1246 int blocklen = -1, width;
1247 unsigned char *data;
1248 cursor = edit->curs1;
1249 col = edit_get_col (edit);
1250 data = g_malloc0 (TEMP_BUF_LEN);
1251 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0)
1253 for (width = 0; width < blocklen; width++)
1255 if (data[width] == '\n')
1256 break;
1258 for (i = 0; i < blocklen; i++)
1260 if (data[i] == '\n')
1261 { /* fill in and move to next line */
1262 int l;
1263 long p;
1264 if (edit_get_byte (edit, edit->curs1) != '\n')
1266 l = width - (edit_get_col (edit) - col);
1267 while (l > 0)
1269 edit_insert (edit, ' ');
1270 l -= space_width;
1273 for (p = edit->curs1;; p++)
1275 if (p == edit->last_byte)
1277 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1278 edit_insert_ahead (edit, '\n');
1279 p++;
1280 break;
1282 if (edit_get_byte (edit, p) == '\n')
1284 p++;
1285 break;
1288 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1289 l = col - edit_get_col (edit);
1290 while (l >= space_width)
1292 edit_insert (edit, ' ');
1293 l -= space_width;
1295 continue;
1297 edit_insert (edit, data[i]);
1300 edit_cursor_move (edit, cursor - edit->curs1);
1301 g_free (data);
1302 edit->force |= REDRAW_PAGE;
1303 return blocklen;
1306 void
1307 edit_block_copy_cmd (WEdit * edit)
1309 long start_mark, end_mark, current = edit->curs1;
1310 int size;
1311 unsigned char *copy_buf;
1313 edit_update_curs_col (edit);
1314 if (eval_marks (edit, &start_mark, &end_mark))
1315 return;
1317 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1319 /* all that gets pushed are deletes hence little space is used on the stack */
1321 edit_push_markers (edit);
1323 if (column_highlighting)
1325 edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1));
1327 else
1329 while (size--)
1330 edit_insert_ahead (edit, copy_buf[size]);
1333 g_free (copy_buf);
1334 edit_scroll_screen_over_cursor (edit);
1336 if (column_highlighting)
1338 edit_set_markers (edit, 0, 0, 0, 0);
1339 edit_push_action (edit, COLUMN_ON);
1340 column_highlighting = 0;
1342 else if (start_mark < current && end_mark > current)
1343 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1345 edit->force |= REDRAW_PAGE;
1349 void
1350 edit_block_move_cmd (WEdit * edit)
1352 long count;
1353 long current;
1354 unsigned char *copy_buf;
1355 long start_mark, end_mark;
1356 int deleted = 0;
1357 int x = 0;
1359 if (eval_marks (edit, &start_mark, &end_mark))
1360 return;
1361 if (column_highlighting)
1363 edit_update_curs_col (edit);
1364 x = edit->curs_col;
1365 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1366 if ((x > edit->column1 && x < edit->column2)
1367 || (x > edit->column2 && x < edit->column1))
1368 return;
1370 else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1371 return;
1373 if ((end_mark - start_mark) > option_max_undo / 2)
1374 if (edit_query_dialog2
1375 (_("Warning"),
1377 ("Block is large, you may not be able to undo this action"),
1378 _("C&ontinue"), _("&Cancel")))
1379 return;
1381 edit_push_markers (edit);
1382 current = edit->curs1;
1383 if (column_highlighting)
1385 long line;
1386 int size, c1, c2;
1387 line = edit->curs_line;
1388 if (edit->mark2 < 0)
1389 edit_mark_cmd (edit, 0);
1390 c1 = min (edit->column1, edit->column2);
1391 c2 = max (edit->column1, edit->column2);
1392 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1393 if (x < c2)
1395 edit_block_delete_cmd (edit);
1396 deleted = 1;
1398 edit_move_to_line (edit, line);
1399 edit_cursor_move (edit,
1400 edit_move_forward3 (edit,
1401 edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
1402 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1403 if (!deleted)
1405 line = edit->curs_line;
1406 edit_update_curs_col (edit);
1407 x = edit->curs_col;
1408 edit_block_delete_cmd (edit);
1409 edit_move_to_line (edit, line);
1410 edit_cursor_move (edit,
1411 edit_move_forward3 (edit,
1412 edit_bol (edit,
1413 edit->curs1), x, 0) - edit->curs1);
1415 edit_set_markers (edit, 0, 0, 0, 0);
1416 edit_push_action (edit, COLUMN_ON);
1417 column_highlighting = 0;
1419 else
1421 copy_buf = g_malloc0 (end_mark - start_mark);
1422 edit_cursor_move (edit, start_mark - edit->curs1);
1423 edit_scroll_screen_over_cursor (edit);
1424 count = start_mark;
1425 while (count < end_mark)
1427 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1428 count++;
1430 edit_scroll_screen_over_cursor (edit);
1431 edit_cursor_move (edit,
1432 current - edit->curs1 -
1433 (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
1434 edit_scroll_screen_over_cursor (edit);
1435 while (count-- > start_mark)
1436 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1437 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
1439 edit_scroll_screen_over_cursor (edit);
1440 g_free (copy_buf);
1441 edit->force |= REDRAW_PAGE;
1444 static void
1445 edit_delete_column_of_text (WEdit * edit)
1447 long p, q, r, m1, m2;
1448 long b, c, d, n;
1450 eval_marks (edit, &m1, &m2);
1451 n = edit_move_forward (edit, m1, 0, m2) + 1;
1452 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1453 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1454 b = max (min (c, d), min (edit->column1, edit->column2));
1455 c = max (c, max (edit->column1, edit->column2));
1457 while (n--)
1459 r = edit_bol (edit, edit->curs1);
1460 p = edit_move_forward3 (edit, r, b, 0);
1461 q = edit_move_forward3 (edit, r, c, 0);
1462 if (p < m1)
1463 p = m1;
1464 if (q > m2)
1465 q = m2;
1466 edit_cursor_move (edit, p - edit->curs1);
1467 while (q > p)
1469 /* delete line between margins */
1470 if (edit_get_byte (edit, edit->curs1) != '\n')
1471 edit_delete (edit, 1);
1472 q--;
1474 if (n)
1475 /* move to next line except on the last delete */
1476 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1480 /* if success return 0 */
1481 static int
1482 edit_block_delete (WEdit * edit)
1484 long count;
1485 long start_mark, end_mark;
1486 int curs_pos, line_width;
1487 long curs_line, c1, c2;
1489 if (eval_marks (edit, &start_mark, &end_mark))
1490 return 0;
1491 if (column_highlighting && edit->mark2 < 0)
1492 edit_mark_cmd (edit, 0);
1493 if ((end_mark - start_mark) > option_max_undo / 2)
1495 /* Warning message with a query to continue or cancel the operation */
1496 if (edit_query_dialog2
1497 (_("Warning"),
1499 ("Block is large, you may not be able to undo this action"),
1500 _("C&ontinue"), _("&Cancel")))
1502 return 1;
1505 c1 = min (edit->column1, edit->column2);
1506 c2 = max (edit->column1, edit->column2);
1507 edit->column1 = c1;
1508 edit->column2 = c2;
1510 edit_push_markers (edit);
1512 curs_line = edit->curs_line;
1514 /* calculate line width and cursor position before cut */
1515 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1516 edit_eol (edit, edit->curs1));
1517 curs_pos = edit->curs_col + edit->over_col;
1519 /* move cursor to start of selection */
1520 edit_cursor_move (edit, start_mark - edit->curs1);
1521 edit_scroll_screen_over_cursor (edit);
1522 count = start_mark;
1523 if (start_mark < end_mark)
1525 if (column_highlighting)
1527 if (edit->mark2 < 0)
1528 edit_mark_cmd (edit, 0);
1529 edit_delete_column_of_text (edit);
1530 /* move cursor to the saved position */
1531 edit_move_to_line (edit, curs_line);
1532 /* calculate line width after cut */
1533 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1534 edit_eol (edit, edit->curs1));
1535 if (option_cursor_beyond_eol && curs_pos > line_width)
1536 edit->over_col = curs_pos - line_width;
1538 else
1540 while (count < end_mark)
1542 edit_delete (edit, 1);
1543 count++;
1547 edit_set_markers (edit, 0, 0, 0, 0);
1548 edit->force |= REDRAW_PAGE;
1549 return 0;
1552 /* returns 1 if canceelled by user */
1554 edit_block_delete_cmd (WEdit * edit)
1556 long start_mark, end_mark;
1557 if (eval_marks (edit, &start_mark, &end_mark))
1559 edit_delete_line (edit);
1560 return 0;
1562 return edit_block_delete (edit);
1565 #define INPUT_INDEX 9
1567 static gboolean
1568 editcmd_find (WEdit * edit, gsize * len)
1570 off_t search_start = edit->search_start;
1571 off_t search_end;
1572 long start_mark = 0;
1573 long end_mark = edit->last_byte;
1574 int mark_res = 0;
1576 if (edit_search_options.only_in_selection)
1578 mark_res = eval_marks (edit, &start_mark, &end_mark);
1579 if (mark_res != 0)
1581 edit->search->error = MC_SEARCH_E_NOTFOUND;
1582 edit->search->error_str = g_strdup (_("Search string not found"));
1583 return FALSE;
1585 if (edit_search_options.backwards)
1587 if (search_start > end_mark || search_start <= start_mark)
1589 search_start = end_mark;
1592 else
1594 if (search_start < start_mark || search_start >= end_mark)
1596 search_start = start_mark;
1600 else
1602 if (edit_search_options.backwards)
1603 end_mark = max (1, edit->curs1) - 1;
1605 if (edit_search_options.backwards)
1607 search_end = end_mark;
1608 while ((int) search_start >= start_mark)
1610 if (search_end > (off_t) (search_start + edit->search->original_len) &&
1611 mc_search_is_fixed_search_str (edit->search))
1613 search_end = search_start + edit->search->original_len;
1615 if (mc_search_run (edit->search, (void *) edit, search_start, search_end, len)
1616 && edit->search->normal_offset == search_start)
1618 return TRUE;
1620 search_start--;
1622 edit->search->error_str = g_strdup (_("Search string not found"));
1624 else
1626 return mc_search_run (edit->search, (void *) edit, search_start, end_mark, len);
1628 return FALSE;
1632 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1633 (and the above) routines to work properly - paul */
1635 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1637 static char *
1638 edit_replace_cmd__conv_to_display (char *str)
1640 #ifdef HAVE_CHARSET
1641 GString *tmp;
1642 tmp = str_convert_to_display (str);
1644 if (tmp && tmp->len)
1646 return g_string_free (tmp, FALSE);
1648 g_string_free (tmp, TRUE);
1649 #endif
1650 return g_strdup (str);
1653 static char *
1654 edit_replace_cmd__conv_to_input (char *str)
1656 #ifdef HAVE_CHARSET
1657 GString *tmp;
1658 tmp = str_convert_to_input (str);
1660 if (tmp && tmp->len)
1662 return g_string_free (tmp, FALSE);
1664 g_string_free (tmp, TRUE);
1665 return g_strdup (str);
1666 #endif
1667 return g_strdup (str);
1670 /* call with edit = 0 before shutdown to close memory leaks */
1671 void
1672 edit_replace_cmd (WEdit * edit, int again)
1674 /* 1 = search string, 2 = replace with */
1675 static char *saved1 = NULL; /* saved default[123] */
1676 static char *saved2 = NULL;
1677 char *input1 = NULL; /* user input from the dialog */
1678 char *input2 = NULL;
1679 char *disp1 = NULL;
1680 char *disp2 = NULL;
1681 int replace_yes;
1682 long times_replaced = 0, last_search;
1683 gboolean once_found = FALSE;
1685 if (!edit)
1687 g_free (saved1), saved1 = NULL;
1688 g_free (saved2), saved2 = NULL;
1689 return;
1692 last_search = edit->last_byte;
1694 edit->force |= REDRAW_COMPLETELY;
1696 if (again && !saved1 && !saved2)
1697 again = 0;
1699 if (again)
1701 input1 = g_strdup (saved1 ? saved1 : "");
1702 input2 = g_strdup (saved2 ? saved2 : "");
1704 else
1706 char *tmp_inp1, *tmp_inp2;
1707 disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
1708 disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
1710 edit_push_action (edit, KEY_PRESS + edit->start_display);
1712 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2);
1714 g_free (disp1);
1715 g_free (disp2);
1717 if (input1 == NULL || *input1 == '\0')
1719 edit->force = REDRAW_COMPLETELY;
1720 goto cleanup;
1723 tmp_inp1 = input1;
1724 tmp_inp2 = input2;
1725 input1 = edit_replace_cmd__conv_to_input (input1);
1726 input2 = edit_replace_cmd__conv_to_input (input2);
1727 g_free (tmp_inp1);
1728 g_free (tmp_inp2);
1730 g_free (saved1), saved1 = g_strdup (input1);
1731 g_free (saved2), saved2 = g_strdup (input2);
1733 if (edit->search)
1735 mc_search_free (edit->search);
1736 edit->search = NULL;
1740 if (!edit->search)
1742 edit->search = mc_search_new (input1, -1);
1743 if (edit->search == NULL)
1745 edit->search_start = edit->curs1;
1746 return;
1748 edit->search->search_type = edit_search_options.type;
1749 edit->search->is_all_charsets = edit_search_options.all_codepages;
1750 edit->search->is_case_sensitive = edit_search_options.case_sens;
1751 edit->search->whole_words = edit_search_options.whole_words;
1752 edit->search->search_fn = edit_search_cmd_callback;
1755 if (edit->found_len && edit->search_start == edit->found_start + 1
1756 && edit_search_options.backwards)
1757 edit->search_start--;
1759 if (edit->found_len && edit->search_start == edit->found_start - 1
1760 && !edit_search_options.backwards)
1761 edit->search_start++;
1765 gsize len = 0;
1766 long new_start;
1768 if (!editcmd_find (edit, &len))
1770 if (!(edit->search->error == MC_SEARCH_E_OK ||
1771 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
1773 edit_error_dialog (_("Search"), edit->search->error_str);
1775 break;
1777 once_found = TRUE;
1778 new_start = edit->search->normal_offset;
1780 edit->search_start = new_start = edit->search->normal_offset;
1781 /*returns negative on not found or error in pattern */
1783 if (edit->search_start >= 0)
1785 guint i;
1787 edit->found_start = edit->search_start;
1788 i = edit->found_len = len;
1790 edit_cursor_move (edit, edit->search_start - edit->curs1);
1791 edit_scroll_screen_over_cursor (edit);
1793 replace_yes = 1;
1795 if (edit->replace_mode == 0)
1797 int l;
1798 l = edit->curs_row - edit->num_widget_lines / 3;
1799 if (l > 0)
1800 edit_scroll_downward (edit, l);
1801 if (l < 0)
1802 edit_scroll_upward (edit, -l);
1804 edit_scroll_screen_over_cursor (edit);
1805 edit->force |= REDRAW_PAGE;
1806 edit_render_keypress (edit);
1808 /*so that undo stops at each query */
1809 edit_push_key_press (edit);
1810 /* and prompt 2/3 down */
1811 disp1 = edit_replace_cmd__conv_to_display (saved1);
1812 disp2 = edit_replace_cmd__conv_to_display (saved2);
1813 switch (editcmd_dialog_replace_prompt_show (edit, disp1, disp2, -1, -1))
1815 case B_ENTER:
1816 replace_yes = 1;
1817 break;
1818 case B_SKIP_REPLACE:
1819 replace_yes = 0;
1820 break;
1821 case B_REPLACE_ALL:
1822 edit->replace_mode = 1;
1823 break;
1824 case B_CANCEL:
1825 replace_yes = 0;
1826 edit->replace_mode = -1;
1827 break;
1829 g_free (disp1);
1830 g_free (disp2);
1832 if (replace_yes)
1833 { /* delete then insert new */
1834 GString *repl_str, *tmp_str;
1835 tmp_str = g_string_new (input2);
1837 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1838 g_string_free (tmp_str, TRUE);
1839 if (edit->search->error != MC_SEARCH_E_OK)
1841 edit_error_dialog (_("Replace"), edit->search->error_str);
1842 break;
1845 while (i--)
1846 edit_delete (edit, 1);
1848 while (++i < repl_str->len)
1849 edit_insert (edit, repl_str->str[i]);
1851 g_string_free (repl_str, TRUE);
1852 edit->found_len = i;
1854 /* so that we don't find the same string again */
1855 if (edit_search_options.backwards)
1857 last_search = edit->search_start;
1858 edit->search_start--;
1860 else
1862 edit->search_start += i;
1863 last_search = edit->last_byte;
1865 edit_scroll_screen_over_cursor (edit);
1867 else
1869 const char *msg = _("Replace");
1870 /* try and find from right here for next search */
1871 edit->search_start = edit->curs1;
1872 edit_update_curs_col (edit);
1874 edit->force |= REDRAW_PAGE;
1875 edit_render_keypress (edit);
1876 if (times_replaced)
1878 message (D_NORMAL, msg, _("%ld replacements made"), times_replaced);
1880 else
1881 query_dialog (msg, _("Search string not found"), D_NORMAL, 1, _("&OK"));
1882 edit->replace_mode = -1;
1885 while (edit->replace_mode >= 0);
1887 edit->force = REDRAW_COMPLETELY;
1888 edit_scroll_screen_over_cursor (edit);
1889 cleanup:
1890 g_free (input1);
1891 g_free (input2);
1895 void
1896 edit_search_cmd (WEdit * edit, int again)
1898 char *search_string = NULL, *search_string_dup = NULL;
1899 gsize len = 0;
1901 if (!edit)
1902 return;
1904 if (edit->search != NULL)
1906 search_string = g_strndup (edit->search->original, edit->search->original_len);
1907 search_string_dup = search_string;
1909 else
1911 GList *history;
1912 history = history_get (MC_HISTORY_SHARED_SEARCH);
1913 if (history != NULL && history->data != NULL)
1915 search_string_dup = search_string = (char *) g_strdup (history->data);
1916 history = g_list_first (history);
1917 g_list_foreach (history, (GFunc) g_free, NULL);
1918 g_list_free (history);
1920 edit->search_start = edit->curs1;
1923 if (!again)
1925 #ifdef HAVE_CHARSET
1926 GString *tmp;
1928 if (search_string && *search_string)
1930 tmp = str_convert_to_display (search_string);
1931 if (tmp != NULL)
1933 if (tmp->len == 0)
1934 g_string_free (tmp, TRUE);
1935 else
1937 g_free (search_string);
1938 search_string = search_string_dup = g_string_free (tmp, FALSE);
1942 #endif /* HAVE_CHARSET */
1943 editcmd_dialog_search_show (edit, &search_string);
1944 g_free (search_string_dup);
1945 search_string_dup = NULL;
1946 #ifdef HAVE_CHARSET
1947 if (search_string && *search_string)
1949 tmp = str_convert_to_input (search_string);
1950 if (tmp != NULL)
1952 if (tmp->len == 0)
1953 g_string_free (tmp, TRUE);
1954 else
1956 g_free (search_string);
1957 search_string = g_string_free (tmp, FALSE);
1961 #endif /* HAVE_CHARSET */
1963 edit_push_action (edit, KEY_PRESS + edit->start_display);
1965 if (search_string == NULL)
1967 edit->force |= REDRAW_COMPLETELY;
1968 edit_scroll_screen_over_cursor (edit);
1969 return;
1972 if (edit->search)
1974 mc_search_free (edit->search);
1975 edit->search = NULL;
1979 if (!edit->search)
1981 edit->search = mc_search_new (search_string, -1);
1982 if (edit->search == NULL)
1984 edit->search_start = edit->curs1;
1985 g_free (search_string);
1986 return;
1989 edit->search->search_type = edit_search_options.type;
1990 edit->search->is_all_charsets = edit_search_options.all_codepages;
1991 edit->search->is_case_sensitive = edit_search_options.case_sens;
1992 edit->search->whole_words = edit_search_options.whole_words;
1993 edit->search->search_fn = edit_search_cmd_callback;
1996 g_free (search_string);
1998 if (search_create_bookmark)
2000 edit_search_cmd_search_create_bookmark (edit);
2002 else
2004 if (edit->found_len && edit->search_start == edit->found_start + 1
2005 && edit_search_options.backwards)
2006 edit->search_start--;
2008 if (edit->found_len && edit->search_start == edit->found_start - 1
2009 && !edit_search_options.backwards)
2010 edit->search_start++;
2012 if (editcmd_find (edit, &len))
2014 edit->found_start = edit->search_start = edit->search->normal_offset;
2015 edit->found_len = len;
2016 edit->over_col = 0;
2017 edit_cursor_move (edit, edit->search_start - edit->curs1);
2018 edit_scroll_screen_over_cursor (edit);
2019 if (edit_search_options.backwards)
2020 edit->search_start--;
2021 else
2022 edit->search_start++;
2024 else
2026 edit->search_start = edit->curs1;
2027 if (edit->search->error_str)
2028 edit_error_dialog (_("Search"), edit->search->error_str);
2032 edit->force |= REDRAW_COMPLETELY;
2033 edit_scroll_screen_over_cursor (edit);
2038 * Check if it's OK to close the editor. If there are unsaved changes,
2039 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2042 edit_ok_to_exit (WEdit * edit)
2044 if (!edit->modified)
2045 return 1;
2047 if (!edit_check_newline (edit))
2048 return 0;
2050 switch (edit_query_dialog3
2051 (_("Quit"), _("File was modified, save with exit?"),
2052 _("&Cancel quit"), _("&Yes"), _("&No")))
2054 case 1:
2055 edit_push_markers (edit);
2056 edit_set_markers (edit, 0, 0, 0, 0);
2057 if (!edit_save_cmd (edit))
2058 return 0;
2059 break;
2060 case 2:
2061 break;
2062 case 0:
2063 case -1:
2064 return 0;
2067 return 1;
2070 /* Return a null terminated length of text. Result must be g_free'd */
2071 static unsigned char *
2072 edit_get_block (WEdit * edit, long start, long finish, int *l)
2074 unsigned char *s, *r;
2075 r = s = g_malloc0 (finish - start + 1);
2076 if (column_highlighting)
2078 *l = 0;
2079 /* copy from buffer, excluding chars that are out of the column 'margins' */
2080 while (start < finish)
2082 int c;
2083 long x;
2084 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
2085 c = edit_get_byte (edit, start);
2086 if ((x >= edit->column1 && x < edit->column2)
2087 || (x >= edit->column2 && x < edit->column1) || c == '\n')
2089 *s++ = c;
2090 (*l)++;
2092 start++;
2095 else
2097 *l = finish - start;
2098 while (start < finish)
2099 *s++ = edit_get_byte (edit, start++);
2101 *s = 0;
2102 return r;
2105 /* save block, returns 1 on success */
2107 edit_save_block (WEdit * edit, const char *filename, long start, long finish)
2109 int len, file;
2111 file = mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2112 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY);
2113 if (file == -1)
2114 return 0;
2116 if (column_highlighting)
2118 int r;
2119 r = mc_write (file, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC));
2120 if (r > 0)
2122 unsigned char *block, *p;
2123 p = block = edit_get_block (edit, start, finish, &len);
2124 while (len)
2126 r = mc_write (file, p, len);
2127 if (r < 0)
2128 break;
2129 p += r;
2130 len -= r;
2132 g_free (block);
2135 else
2137 unsigned char *buf;
2138 int i = start, end;
2139 len = finish - start;
2140 buf = g_malloc0 (TEMP_BUF_LEN);
2141 while (start != finish)
2143 end = min (finish, start + TEMP_BUF_LEN);
2144 for (; i < end; i++)
2145 buf[i - start] = edit_get_byte (edit, i);
2146 len -= mc_write (file, (char *) buf, end - start);
2147 start = end;
2149 g_free (buf);
2151 mc_close (file);
2152 if (len)
2153 return 0;
2154 return 1;
2157 /* copies a block to clipboard file */
2158 static int
2159 edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
2161 int ret;
2162 gchar *tmp;
2163 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2164 ret = edit_save_block (edit, tmp, start, finish);
2165 g_free (tmp);
2166 return ret;
2169 void
2170 edit_paste_from_history (WEdit * edit)
2172 (void) edit;
2173 edit_error_dialog (_("Error"), _("This function is not implemented"));
2177 edit_copy_to_X_buf_cmd (WEdit * edit)
2179 long start_mark, end_mark;
2180 if (eval_marks (edit, &start_mark, &end_mark))
2181 return 0;
2182 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2184 edit_error_dialog (_("Copy to clipboard"),
2185 get_sys_error (_("Unable to save to file")));
2186 return 1;
2188 /* try use external clipboard utility */
2189 copy_file_to_ext_clip ();
2191 edit_mark_cmd (edit, 1);
2192 return 0;
2196 edit_cut_to_X_buf_cmd (WEdit * edit)
2198 long start_mark, end_mark;
2199 if (eval_marks (edit, &start_mark, &end_mark))
2200 return 0;
2201 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2203 edit_error_dialog (_("Cut to clipboard"), _("Unable to save to file"));
2204 return 1;
2206 /* try use external clipboard utility */
2207 copy_file_to_ext_clip ();
2209 edit_block_delete_cmd (edit);
2210 edit_mark_cmd (edit, 1);
2211 return 0;
2214 void
2215 edit_paste_from_X_buf_cmd (WEdit * edit)
2217 gchar *tmp;
2218 /* try use external clipboard utility */
2219 paste_to_file_from_ext_clip ();
2220 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2221 edit_insert_file (edit, tmp);
2222 g_free (tmp);
2227 * Ask user for the line and go to that line.
2228 * Negative numbers mean line from the end (i.e. -1 is the last line).
2230 void
2231 edit_goto_cmd (WEdit * edit)
2233 char *f;
2234 static long line = 0; /* line as typed, saved as default */
2235 long l;
2236 char *error;
2237 char s[32];
2239 g_snprintf (s, sizeof (s), "%ld", line);
2240 f = input_dialog (_("Goto line"), _("Enter line:"), MC_HISTORY_EDIT_GOTO_LINE,
2241 line ? s : "");
2242 if (!f)
2243 return;
2245 if (!*f)
2247 g_free (f);
2248 return;
2251 l = strtol (f, &error, 0);
2252 if (*error)
2254 g_free (f);
2255 return;
2258 line = l;
2259 if (l < 0)
2260 l = edit->total_lines + l + 2;
2261 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
2262 edit_move_to_line (edit, l - 1);
2263 edit->force |= REDRAW_COMPLETELY;
2264 g_free (f);
2268 /* Return 1 on success */
2270 edit_save_block_cmd (WEdit * edit)
2272 long start_mark, end_mark;
2273 char *exp, *tmp;
2275 if (eval_marks (edit, &start_mark, &end_mark))
2276 return 1;
2278 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2279 exp =
2280 input_expand_dialog (_("Save block"), _("Enter file name:"),
2281 MC_HISTORY_EDIT_SAVE_BLOCK, tmp);
2282 g_free (tmp);
2283 edit_push_action (edit, KEY_PRESS + edit->start_display);
2284 if (exp)
2286 if (!*exp)
2288 g_free (exp);
2289 return 0;
2291 else
2293 if (edit_save_block (edit, exp, start_mark, end_mark))
2295 g_free (exp);
2296 edit->force |= REDRAW_COMPLETELY;
2297 return 1;
2299 else
2301 g_free (exp);
2302 edit_error_dialog (_("Save block"), get_sys_error (_("Cannot save file")));
2306 edit->force |= REDRAW_COMPLETELY;
2307 return 0;
2311 /* returns 1 on success */
2313 edit_insert_file_cmd (WEdit * edit)
2315 gchar *tmp;
2316 char *exp;
2318 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2319 exp = input_expand_dialog (_("Insert file"), _("Enter file name:"),
2320 MC_HISTORY_EDIT_INSERT_FILE, tmp);
2321 g_free (tmp);
2322 edit_push_action (edit, KEY_PRESS + edit->start_display);
2323 if (exp)
2325 if (!*exp)
2327 g_free (exp);
2328 return 0;
2330 else
2332 if (edit_insert_file (edit, exp))
2334 g_free (exp);
2335 edit->force |= REDRAW_COMPLETELY;
2336 return 1;
2338 else
2340 g_free (exp);
2341 edit_error_dialog (_("Insert file"), get_sys_error (_("Cannot insert file")));
2345 edit->force |= REDRAW_COMPLETELY;
2346 return 0;
2349 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2351 edit_sort_cmd (WEdit * edit)
2353 static char *old = 0;
2354 char *exp, *tmp;
2355 long start_mark, end_mark;
2356 int e;
2358 if (eval_marks (edit, &start_mark, &end_mark))
2360 edit_error_dialog (_("Sort block"), _("You must first highlight a block of text"));
2361 return 0;
2364 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2365 edit_save_block (edit, tmp, start_mark, end_mark);
2366 g_free (tmp);
2368 exp = input_dialog (_("Run sort"),
2369 _("Enter sort options (see manpage) separated by whitespace:"),
2370 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2372 if (!exp)
2373 return 1;
2374 g_free (old);
2375 old = exp;
2376 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2377 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2378 e = system (tmp);
2379 g_free (tmp);
2380 if (e)
2382 if (e == -1 || e == 127)
2384 edit_error_dialog (_("Sort"), get_sys_error (_("Cannot execute sort command")));
2386 else
2388 char q[8];
2389 sprintf (q, "%d ", e);
2390 tmp = g_strdup_printf (_("Sort returned non-zero: %s"), q);
2391 edit_error_dialog (_("Sort"), tmp);
2392 g_free (tmp);
2394 return -1;
2397 edit->force |= REDRAW_COMPLETELY;
2399 if (edit_block_delete_cmd (edit))
2400 return 1;
2401 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2402 edit_insert_file (edit, tmp);
2403 g_free (tmp);
2404 return 0;
2408 * Ask user for a command, execute it and paste its output back to the
2409 * editor.
2412 edit_ext_cmd (WEdit * edit)
2414 char *exp, *tmp;
2415 int e;
2417 exp =
2418 input_dialog (_("Paste output of external command"),
2419 _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2421 if (!exp)
2422 return 1;
2424 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2425 e = system (tmp);
2426 g_free (tmp);
2427 g_free (exp);
2429 if (e)
2431 edit_error_dialog (_("External command"), get_sys_error (_("Cannot execute command")));
2432 return -1;
2435 edit->force |= REDRAW_COMPLETELY;
2436 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2437 edit_insert_file (edit, tmp);
2438 g_free (tmp);
2439 return 0;
2442 /* if block is 1, a block must be highlighted and the shell command
2443 processes it. If block is 0 the shell command is a straight system
2444 command, that just produces some output which is to be inserted */
2445 void
2446 edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2448 long start_mark, end_mark;
2449 char buf[BUFSIZ];
2450 FILE *script_home = NULL;
2451 FILE *block_file = NULL;
2452 gchar *o, *h, *b, *tmp;
2453 char *quoted_name = NULL;
2455 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2456 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2457 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2459 script_home = fopen (h, "r");
2460 if (script_home == NULL)
2462 FILE *script_src = NULL;
2464 script_home = fopen (h, "w");
2465 if (script_home == NULL)
2467 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2468 edit_error_dialog ("", get_sys_error (tmp));
2469 g_free (tmp);
2470 goto edit_block_process_cmd__EXIT;
2473 script_src = fopen (o, "r");
2474 if (script_src == NULL)
2476 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2477 script_src = fopen (o, "r");
2478 if (script_src == NULL)
2480 fclose (script_home);
2481 unlink (h);
2482 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2483 edit_error_dialog ("", get_sys_error (tmp));
2484 g_free (tmp);
2485 goto edit_block_process_cmd__EXIT;
2488 while (fgets (buf, sizeof (buf), script_src))
2489 fputs (buf, script_home);
2490 fclose (script_src);
2492 if (fclose (script_home))
2494 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2495 edit_error_dialog ("", get_sys_error (tmp));
2496 g_free (tmp);
2497 goto edit_block_process_cmd__EXIT;
2499 chmod (h, 0700);
2500 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2501 edit_error_dialog ("", get_sys_error (tmp));
2502 g_free (tmp);
2505 open_error_pipe ();
2507 if (block)
2508 { /* for marked block run indent formatter */
2509 if (eval_marks (edit, &start_mark, &end_mark))
2511 edit_error_dialog (_("Process block"),
2512 _("You must first highlight a block of text"));
2513 goto edit_block_process_cmd__EXIT;
2515 edit_save_block (edit, b, start_mark, end_mark);
2516 quoted_name = name_quote (edit->filename, 0);
2518 * Run script.
2519 * Initial space is to avoid polluting bash history.
2520 * Arguments:
2521 * $1 - name of the edited file (to check its extension etc).
2522 * $2 - file containing the current block.
2523 * $3 - file where error messages should be put
2524 * (for compatibility with old scripts).
2526 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2527 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2529 else
2532 * No block selected, just execute the command for the file.
2533 * Arguments:
2534 * $1 - name of the edited file.
2536 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2537 quoted_name, (char *) NULL);
2540 if (system (tmp) == -1)
2542 edit_error_dialog (_("Process block"), _("Error calling program"));
2544 else
2547 g_free (quoted_name);
2548 close_error_pipe (D_NORMAL, NULL);
2550 edit_refresh_cmd (edit);
2551 edit->force |= REDRAW_COMPLETELY;
2553 /* insert result block */
2554 if (block && !edit_block_delete_cmd (edit))
2556 edit_insert_file (edit, b);
2557 block_file = fopen (b, "w");
2558 if (block_file != NULL)
2559 fclose (block_file);
2562 g_free (tmp);
2564 edit_block_process_cmd__EXIT:
2565 g_free (b);
2566 g_free (h);
2567 g_free (o);
2570 /* prints at the cursor */
2571 /* returns the number of chars printed */
2573 edit_print_string (WEdit * e, const char *s)
2575 size_t i = 0;
2576 while (s[i] != '\0')
2577 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2578 e->force |= REDRAW_COMPLETELY;
2579 edit_update_screen (e);
2580 return i;
2584 static void
2585 pipe_mail (WEdit * edit, char *to, char *subject, char *cc)
2587 FILE *p = 0;
2588 char *s;
2590 to = name_quote (to, 0);
2591 subject = name_quote (subject, 0);
2592 cc = name_quote (cc, 0);
2593 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "", cc, " ", to, (char *) NULL);
2594 g_free (to);
2595 g_free (subject);
2596 g_free (cc);
2598 if (s)
2600 p = popen (s, "w");
2601 g_free (s);
2604 if (p)
2606 long i;
2607 for (i = 0; i < edit->last_byte; i++)
2608 fputc (edit_get_byte (edit, i), p);
2609 pclose (p);
2613 #define MAIL_DLG_HEIGHT 12
2615 void
2616 edit_mail_dialog (WEdit * edit)
2618 char *tmail_to;
2619 char *tmail_subject;
2620 char *tmail_cc;
2622 static char *mail_cc_last = 0;
2623 static char *mail_subject_last = 0;
2624 static char *mail_to_last = 0;
2626 QuickWidget quick_widgets[] = {
2627 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2628 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2629 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2630 /* 3 */ QUICK_LABEL (3, 50, 7, MAIL_DLG_HEIGHT, N_("Copies to")),
2631 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2",
2632 &tmail_subject),
2633 /* 5 */ QUICK_LABEL (3, 50, 5, MAIL_DLG_HEIGHT, N_("Subject")),
2634 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2635 /* 7 */ QUICK_LABEL (3, 50, 3, MAIL_DLG_HEIGHT, N_("To")),
2636 /* 8 */ QUICK_LABEL (3, 50, 2, MAIL_DLG_HEIGHT, N_("mail -s <subject> -c <cc> <to>")),
2637 QUICK_END
2640 QuickDialog Quick_input = {
2641 50, MAIL_DLG_HEIGHT, -1, -1, N_("Mail"),
2642 "[Input Line Keys]", quick_widgets, FALSE
2645 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2646 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2647 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2649 if (quick_dialog (&Quick_input) != B_CANCEL)
2651 g_free (mail_cc_last);
2652 g_free (mail_subject_last);
2653 g_free (mail_to_last);
2654 mail_cc_last = tmail_cc;
2655 mail_subject_last = tmail_subject;
2656 mail_to_last = tmail_to;
2657 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2662 /*******************/
2663 /* Word Completion */
2664 /*******************/
2666 static gboolean
2667 is_break_char (char c)
2669 return (isspace (c) || strchr ("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2672 /* find first character of current word */
2673 static int
2674 edit_find_word_start (WEdit * edit, long *word_start, gsize * word_len)
2676 int c, last;
2677 gsize i;
2679 /* return if at begin of file */
2680 if (edit->curs1 <= 0)
2681 return 0;
2683 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2684 /* return if not at end or in word */
2685 if (is_break_char (c))
2686 return 0;
2688 /* search start of word to be completed */
2689 for (i = 2;; i++)
2691 /* return if at begin of file */
2692 if ((gsize) edit->curs1 < i)
2693 return 0;
2695 last = c;
2696 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2698 if (is_break_char (c))
2700 /* return if word starts with digit */
2701 if (isdigit (last))
2702 return 0;
2704 *word_start = edit->curs1 - (i - 1); /* start found */
2705 *word_len = i - 1;
2706 break;
2709 /* success */
2710 return 1;
2713 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2715 /* collect the possible completions */
2716 static gsize
2717 edit_collect_completions (WEdit * edit, long start, gsize word_len,
2718 char *match_expr, struct selection *compl, gsize * num)
2720 gsize len = 0;
2721 gsize max_len = 0;
2722 gsize i;
2723 int skip;
2724 GString *temp;
2725 mc_search_t *srch;
2727 long last_byte;
2729 srch = mc_search_new (match_expr, -1);
2730 if (srch == NULL)
2731 return 0;
2733 if (mc_config_get_bool
2734 (mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0))
2736 last_byte = edit->last_byte;
2738 else
2740 last_byte = start;
2743 srch->search_type = MC_SEARCH_T_REGEX;
2744 srch->is_case_sensitive = TRUE;
2745 srch->search_fn = edit_search_cmd_callback;
2747 /* collect max MAX_WORD_COMPLETIONS completions */
2748 start = -1;
2749 while (1)
2751 /* get next match */
2752 if (mc_search_run (srch, (void *) edit, start + 1, last_byte, &len) == FALSE)
2753 break;
2754 start = srch->normal_offset;
2756 /* add matched completion if not yet added */
2757 temp = g_string_new ("");
2758 for (i = 0; i < len; i++)
2760 skip = edit_get_byte (edit, start + i);
2761 if (isspace (skip))
2762 continue;
2763 g_string_append_c (temp, skip);
2766 skip = 0;
2768 for (i = 0; i < (gsize) * num; i++)
2770 if (strncmp
2771 ((char *) &compl[i].text[word_len],
2772 (char *) &temp->str[word_len], max (len, compl[i].len) - (gsize) word_len) == 0)
2774 struct selection this = compl[i];
2775 for (++i; i < *num; i++)
2777 compl[i - 1] = compl[i];
2779 compl[*num - 1] = this;
2780 skip = 1;
2781 break; /* skip it, already added */
2784 if (skip)
2786 g_string_free (temp, TRUE);
2787 continue;
2789 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS)
2791 g_free (compl[0].text);
2792 for (i = 1; i < *num; i++)
2794 compl[i - 1] = compl[i];
2796 (*num)--;
2798 #ifdef HAVE_CHARSET
2800 GString *recoded;
2801 recoded = str_convert_to_display (temp->str);
2803 if (recoded && recoded->len)
2805 g_string_free (temp, TRUE);
2806 temp = recoded;
2808 else
2809 g_string_free (recoded, TRUE);
2811 #endif
2812 compl[*num].text = temp->str;
2813 compl[*num].len = temp->len;
2814 (*num)++;
2815 start += len;
2816 g_string_free (temp, FALSE);
2818 /* note the maximal length needed for the completion dialog */
2819 if (len > max_len)
2820 max_len = len;
2822 mc_search_free (srch);
2823 return max_len;
2827 * Complete current word using regular expression search
2828 * backwards beginning at the current cursor position.
2830 void
2831 edit_complete_word_cmd (WEdit * edit)
2833 gsize i, max_len, word_len = 0, num_compl = 0;
2834 long word_start = 0;
2835 unsigned char *bufpos;
2836 char *match_expr;
2837 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2839 /* search start of word to be completed */
2840 if (!edit_find_word_start (edit, &word_start, &word_len))
2841 return;
2843 /* prepare match expression */
2844 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
2846 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2847 match_expr =
2848 g_strdup_printf
2849 ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+",
2850 (int) word_len, bufpos);
2852 /* collect the possible completions */
2853 /* start search from begin to end of file */
2854 max_len =
2855 edit_collect_completions (edit, word_start, word_len, match_expr,
2856 (struct selection *) &compl, &num_compl);
2858 if (num_compl > 0)
2860 /* insert completed word if there is only one match */
2861 if (num_compl == 1)
2863 for (i = word_len; i < compl[0].len; i++)
2864 edit_insert (edit, *(compl[0].text + i));
2866 /* more than one possible completion => ask the user */
2867 else
2869 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2870 /* !!! pressed again the selection dialog pops up, but that !!! */
2871 /* !!! seems to require a further internal state !!! */
2872 /*tty_beep (); */
2874 /* let the user select the preferred completion */
2875 editcmd_dialog_completion_show (edit, max_len, word_len,
2876 (struct selection *) &compl, num_compl);
2880 g_free (match_expr);
2881 /* release memory before return */
2882 for (i = 0; i < num_compl; i++)
2883 g_free (compl[i].text);
2886 void
2887 edit_select_codepage_cmd (WEdit * edit)
2889 #ifdef HAVE_CHARSET
2890 if (do_select_codepage ())
2891 edit_set_codeset (edit);
2893 edit->force = REDRAW_COMPLETELY;
2894 edit_refresh_cmd (edit);
2895 #else
2896 (void) edit;
2897 #endif
2900 void
2901 edit_insert_literal_cmd (WEdit * edit)
2903 int char_for_insertion = editcmd_dialog_raw_key_query (_("Insert literal"),
2904 _("Press any key:"), 0);
2905 edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
2908 void
2909 edit_execute_macro_cmd (WEdit * edit)
2911 int command =
2912 CK_Macro (editcmd_dialog_raw_key_query (_("Execute macro"), _("Press macro hotkey:"),
2913 1));
2914 if (command == CK_Macro (0))
2915 command = CK_Insert_Char;
2917 edit_execute_key_command (edit, command, -1);
2920 void
2921 edit_begin_end_macro_cmd (WEdit * edit)
2923 /* edit is a pointer to the widget */
2924 if (edit)
2926 unsigned long command = edit->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2927 edit_execute_key_command (edit, command, -1);
2932 edit_load_forward_cmd (WEdit * edit)
2934 if (edit->modified)
2936 if (edit_query_dialog2
2937 (_("Warning"),
2938 _("Current text was modified without a file save\n"
2939 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")))
2941 edit->force |= REDRAW_COMPLETELY;
2942 return 0;
2945 if (edit_stack_iterator + 1 < MAX_HISTORY_MOVETO)
2947 if (edit_history_moveto[edit_stack_iterator + 1].line < 1)
2949 return 1;
2951 edit_stack_iterator++;
2952 if (edit_history_moveto[edit_stack_iterator].filename)
2954 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2955 edit_history_moveto[edit_stack_iterator].line);
2956 return 0;
2958 else
2960 return 1;
2963 else
2965 return 1;
2970 edit_load_back_cmd (WEdit * edit)
2972 if (edit->modified)
2974 if (edit_query_dialog2
2975 (_("Warning"),
2976 _("Current text was modified without a file save\n"
2977 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")))
2979 edit->force |= REDRAW_COMPLETELY;
2980 return 0;
2983 if (edit_stack_iterator > 0)
2985 edit_stack_iterator--;
2986 if (edit_history_moveto[edit_stack_iterator].filename)
2988 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2989 edit_history_moveto[edit_stack_iterator].line);
2990 return 0;
2992 else
2994 return 1;
2997 else
2999 return 1;
3003 void
3004 edit_get_match_keyword_cmd (WEdit * edit)
3006 gsize word_len = 0, max_len = 0;
3007 int num_def = 0;
3008 int i;
3009 long word_start = 0;
3010 unsigned char *bufpos;
3011 char *match_expr;
3012 char *path = NULL;
3013 char *ptr = NULL;
3014 char *tagfile = NULL;
3016 etags_hash_t def_hash[MAX_DEFINITIONS];
3018 for (i = 0; i < MAX_DEFINITIONS; i++)
3020 def_hash[i].filename = NULL;
3023 /* search start of word to be completed */
3024 if (!edit_find_word_start (edit, &word_start, &word_len))
3025 return;
3027 /* prepare match expression */
3028 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
3029 match_expr = g_strdup_printf ("%.*s", (int) word_len, bufpos);
3031 ptr = g_get_current_dir ();
3032 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
3033 g_free (ptr);
3035 /* Recursive search file 'TAGS' in parent dirs */
3038 ptr = g_path_get_dirname (path);
3039 g_free (path);
3040 path = ptr;
3041 g_free (tagfile);
3042 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
3043 if (exist_file (tagfile))
3044 break;
3046 while (strcmp (path, G_DIR_SEPARATOR_S) != 0);
3048 if (tagfile)
3050 num_def =
3051 etags_set_definition_hash (tagfile, path, match_expr, (etags_hash_t *) & def_hash);
3052 g_free (tagfile);
3054 g_free (path);
3056 max_len = MAX_WIDTH_DEF_DIALOG;
3057 word_len = 0;
3058 if (num_def > 0)
3060 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
3061 (etags_hash_t *) & def_hash, num_def);
3063 g_free (match_expr);
3066 void
3067 edit_move_block_to_right (WEdit * edit)
3069 long start_mark, end_mark;
3070 long cur_bol, start_bol;
3072 if (eval_marks (edit, &start_mark, &end_mark))
3073 return;
3075 start_bol = edit_bol (edit, start_mark);
3076 cur_bol = edit_bol (edit, end_mark - 1);
3079 edit_cursor_move (edit, cur_bol - edit->curs1);
3080 if (option_fill_tabs_with_spaces)
3082 if (option_fake_half_tabs)
3084 insert_spaces_tab (edit, 1);
3086 else
3088 insert_spaces_tab (edit, 0);
3091 else
3093 edit_insert (edit, '\t');
3095 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
3096 if (cur_bol == 0)
3098 break;
3100 cur_bol = edit_bol (edit, cur_bol - 1);
3102 while (cur_bol >= start_bol);
3103 edit->force |= REDRAW_PAGE;
3106 void
3107 edit_move_block_to_left (WEdit * edit)
3109 long start_mark, end_mark;
3110 long cur_bol, start_bol;
3111 int i, del_tab_width;
3112 int next_char;
3114 if (eval_marks (edit, &start_mark, &end_mark))
3115 return;
3117 start_bol = edit_bol (edit, start_mark);
3118 cur_bol = edit_bol (edit, end_mark - 1);
3121 edit_cursor_move (edit, cur_bol - edit->curs1);
3122 if (option_fake_half_tabs)
3124 del_tab_width = HALF_TAB_SIZE;
3126 else
3128 del_tab_width = option_tab_spacing;
3130 next_char = edit_get_byte (edit, edit->curs1);
3131 if (next_char == '\t')
3133 edit_delete (edit, 1);
3135 else if (next_char == ' ')
3137 for (i = 1; i <= del_tab_width; i++)
3139 if (next_char == ' ')
3141 edit_delete (edit, 1);
3143 next_char = edit_get_byte (edit, edit->curs1);
3146 if (cur_bol == 0)
3148 break;
3150 cur_bol = edit_bol (edit, cur_bol - 1);
3152 while (cur_bol >= start_bol);
3153 edit->force |= REDRAW_PAGE;