Code optimization: avoid lot of calls for alloc/free memory in cycle.
[midnight-commander.git] / src / editor / editcmd.c
bloba73b3d98e858cd73e1d2774c13348ccfd9619dbb
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/mc-vfs/vfs.h"
57 #include "lib/widget.h"
58 #include "lib/charsets.h"
60 #include "src/filemanager/layout.h" /* clr_scr() */
62 #include "src/history.h"
63 #include "src/main.h" /* mc_home, midnight_shutdown */
64 #include "src/setup.h" /* option_tab_spacing */
65 #include "src/help.h" /* interactive_display() */
66 #include "src/selcodepage.h"
67 #include "src/keybind-defaults.h"
68 #include "src/clipboard.h" /* copy_file_to_ext_clip, paste_to_file_from_ext_clip */
70 #include "edit-impl.h"
71 #include "edit-widget.h"
72 #include "editcmd_dialogs.h"
73 #include "etags.h"
75 /*** global variables ****************************************************************************/
77 /* search and replace: */
78 int search_create_bookmark = FALSE;
80 /* queries on a save */
81 int edit_confirm_save = 1;
83 static int edit_save_cmd (WEdit * edit);
84 static unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l);
86 /*** file scope macro definitions ****************************************************************/
88 #define space_width 1
90 #define TEMP_BUF_LEN 1024
92 #define INPUT_INDEX 9
94 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
95 (and the above) routines to work properly - paul */
97 #define is_digit(x) ((x) >= '0' && (x) <= '9')
99 #define MAIL_DLG_HEIGHT 12
101 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
103 /*** file scope type declarations ****************************************************************/
105 /*** file scope variables ************************************************************************/
107 /*** file scope functions ************************************************************************/
108 /* --------------------------------------------------------------------------------------------- */
110 /* If 0 (quick save) then a) create/truncate <filename> file,
111 b) save to <filename>;
112 if 1 (safe save) then a) save to <tempnam>,
113 b) rename <tempnam> to <filename>;
114 if 2 (do backups) then a) save to <tempnam>,
115 b) rename <filename> to <filename.backup_ext>,
116 c) rename <tempnam> to <filename>. */
118 /* returns 0 on error, -1 on abort */
120 static int
121 edit_save_file (WEdit * edit, const char *filename)
123 char *p;
124 gchar *tmp;
125 long filelen = 0;
126 char *savename = 0;
127 gchar *real_filename;
128 int this_save_mode, fd = -1;
130 if (!filename)
131 return 0;
132 if (!*filename)
133 return 0;
135 if (*filename != PATH_SEP && edit->dir)
137 real_filename = concat_dir_and_file (edit->dir, filename);
139 else
141 real_filename = g_strdup (filename);
144 this_save_mode = option_save_mode;
145 if (this_save_mode != EDIT_QUICK_SAVE)
147 if (!vfs_file_is_local (real_filename) ||
148 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1)
151 * The file does not exists yet, so no safe save or
152 * backup are necessary.
154 this_save_mode = EDIT_QUICK_SAVE;
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 /* {{{ Macro stuff starts here */
450 /* --------------------------------------------------------------------------------------------- */
451 /** creates a macro file if it doesn't exist */
453 static FILE *
454 edit_open_macro_file (const char *r)
456 gchar *filename;
457 FILE *fd;
458 int file;
459 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
460 file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
461 if (file == -1)
463 g_free (filename);
464 return 0;
466 close (file);
467 fd = fopen (filename, r);
468 g_free (filename);
469 return fd;
472 #define MAX_MACROS 1024
473 static int saved_macro[MAX_MACROS + 1];
474 static int saved_macros_loaded = 0;
476 /* --------------------------------------------------------------------------------------------- */
478 This is just to stop the macro file be loaded over and over for keys
479 that aren't defined to anything. On slow systems this could be annoying.
482 static int
483 macro_exists (int k)
485 int i;
486 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
487 if (saved_macro[i] == k)
488 return i;
489 return -1;
492 /* --------------------------------------------------------------------------------------------- */
493 /** returns 1 on error */
495 static int
496 edit_delete_macro (WEdit * edit, int k)
498 gchar *tmp, *tmp2;
499 struct macro macro[MAX_MACRO_LENGTH];
500 FILE *f, *g;
501 int s, i, n, j = 0;
503 (void) edit;
505 if (saved_macros_loaded)
507 j = macro_exists (k);
508 if (j < 0)
509 return 0;
511 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
512 g = fopen (tmp, "w");
513 g_free (tmp);
514 if (!g)
516 edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot open temp file")));
517 return 1;
519 f = edit_open_macro_file ("r");
520 if (!f)
522 edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot open macro file")));
523 fclose (g);
524 return 1;
526 for (;;)
528 n = fscanf (f, ("key '%d 0': "), &s);
529 if (!n || n == EOF)
530 break;
531 n = 0;
532 while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
533 n++;
535 int ret;
536 ret = fscanf (f, ";\n");
538 if (s != k)
540 fprintf (g, ("key '%d 0': "), s);
541 for (i = 0; i < n; i++)
542 fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
543 fprintf (g, ";\n");
546 fclose (f);
547 fclose (g);
548 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
549 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
550 if (rename (tmp, tmp2) == -1)
552 edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot overwrite macro file")));
553 g_free (tmp);
554 g_free (tmp2);
555 return 1;
557 g_free (tmp);
558 g_free (tmp2);
560 if (saved_macros_loaded)
561 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
562 return 0;
565 /* }}} */
567 /* --------------------------------------------------------------------------------------------- */
568 /** returns 1 on success */
570 static int
571 edit_save_cmd (WEdit * edit)
573 int res, save_lock = 0;
575 if (!edit->locked && !edit->delete_file)
576 save_lock = edit_lock_file (edit);
577 res = edit_save_file (edit, edit->filename);
579 /* Maintain modify (not save) lock on failure */
580 if ((res > 0 && edit->locked) || save_lock)
581 edit->locked = edit_unlock_file (edit);
583 /* On failure try 'save as', it does locking on its own */
584 if (!res)
585 return edit_save_as_cmd (edit);
586 edit->force |= REDRAW_COMPLETELY;
587 if (res > 0)
589 edit->delete_file = 0;
590 edit->modified = 0;
593 return 1;
596 /* --------------------------------------------------------------------------------------------- */
597 /** returns 1 on error */
599 static int
600 edit_load_file_from_filename (WEdit * edit, char *exp)
602 int prev_locked = edit->locked;
603 char *prev_filename = g_strdup (edit->filename);
605 if (!edit_reload (edit, exp))
607 g_free (prev_filename);
608 return 1;
611 if (prev_locked)
613 char *fullpath;
615 fullpath = g_build_filename (edit->dir, prev_filename, (char *) NULL);
616 unlock_file (fullpath);
617 g_free (fullpath);
619 g_free (prev_filename);
620 return 0;
623 /* --------------------------------------------------------------------------------------------- */
625 static void
626 edit_load_syntax_file (WEdit * edit)
628 char *extdir;
629 int dir = 0;
631 if (geteuid () == 0)
633 dir = query_dialog (_("Syntax file edit"),
634 _("Which syntax file you want to edit?"), D_NORMAL, 2,
635 _("&User"), _("&System Wide"));
638 extdir = g_build_filename (mc_home, "syntax", "Syntax", (char *) NULL);
639 if (!exist_file (extdir))
641 g_free (extdir);
642 extdir = g_build_filename (mc_home_alt, "syntax", "Syntax", (char *) NULL);
645 if (dir == 0)
647 char *buffer;
649 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
650 check_for_default (extdir, buffer);
651 edit_load_file_from_filename (edit, buffer);
652 g_free (buffer);
654 else if (dir == 1)
655 edit_load_file_from_filename (edit, extdir);
657 g_free (extdir);
660 /* --------------------------------------------------------------------------------------------- */
662 static void
663 edit_load_menu_file (WEdit * edit)
665 char *buffer;
666 char *menufile;
667 int dir = 0;
669 dir = query_dialog (_("Menu edit"),
670 _("Which menu file do you want to edit?"), D_NORMAL,
671 geteuid () != 0 ? 2 : 3, _("&Local"), _("&User"), _("&System Wide"));
673 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
675 if (!exist_file (menufile))
677 g_free (menufile);
678 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
681 switch (dir)
683 case 0:
684 buffer = g_strdup (EDIT_LOCAL_MENU);
685 check_for_default (menufile, buffer);
686 chmod (buffer, 0600);
687 break;
689 case 1:
690 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
691 check_for_default (menufile, buffer);
692 break;
694 case 2:
695 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
696 if (!exist_file (buffer))
698 g_free (buffer);
699 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
701 break;
703 default:
704 g_free (menufile);
705 return;
708 edit_load_file_from_filename (edit, buffer);
710 g_free (buffer);
711 g_free (menufile);
714 /* --------------------------------------------------------------------------------------------- */
716 static void
717 edit_delete_column_of_text (WEdit * edit)
719 long p, q, r, m1, m2;
720 long b, c, d, n;
722 eval_marks (edit, &m1, &m2);
723 n = edit_move_forward (edit, m1, 0, m2) + 1;
724 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
725 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
726 b = max (min (c, d), min (edit->column1, edit->column2));
727 c = max (c, max (edit->column1, edit->column2));
729 while (n--)
731 r = edit_bol (edit, edit->curs1);
732 p = edit_move_forward3 (edit, r, b, 0);
733 q = edit_move_forward3 (edit, r, c, 0);
734 if (p < m1)
735 p = m1;
736 if (q > m2)
737 q = m2;
738 edit_cursor_move (edit, p - edit->curs1);
739 while (q > p)
741 /* delete line between margins */
742 if (edit_get_byte (edit, edit->curs1) != '\n')
743 edit_delete (edit, 1);
744 q--;
746 if (n)
747 /* move to next line except on the last delete */
748 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
752 /* --------------------------------------------------------------------------------------------- */
753 /** if success return 0 */
755 static int
756 edit_block_delete (WEdit * edit)
758 long count;
759 long start_mark, end_mark;
760 int curs_pos, line_width;
761 long curs_line, c1, c2;
763 if (eval_marks (edit, &start_mark, &end_mark))
764 return 0;
765 if (edit->column_highlight && edit->mark2 < 0)
766 edit_mark_cmd (edit, 0);
767 if ((end_mark - start_mark) > option_max_undo / 2)
769 /* Warning message with a query to continue or cancel the operation */
770 if (edit_query_dialog2
771 (_("Warning"),
773 ("Block is large, you may not be able to undo this action"),
774 _("C&ontinue"), _("&Cancel")))
776 return 1;
779 c1 = min (edit->column1, edit->column2);
780 c2 = max (edit->column1, edit->column2);
781 edit->column1 = c1;
782 edit->column2 = c2;
784 edit_push_markers (edit);
786 curs_line = edit->curs_line;
788 /* calculate line width and cursor position before cut */
789 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
790 edit_eol (edit, edit->curs1));
791 curs_pos = edit->curs_col + edit->over_col;
793 /* move cursor to start of selection */
794 edit_cursor_move (edit, start_mark - edit->curs1);
795 edit_scroll_screen_over_cursor (edit);
796 count = start_mark;
797 if (start_mark < end_mark)
799 if (edit->column_highlight)
801 if (edit->mark2 < 0)
802 edit_mark_cmd (edit, 0);
803 edit_delete_column_of_text (edit);
804 /* move cursor to the saved position */
805 edit_move_to_line (edit, curs_line);
806 /* calculate line width after cut */
807 line_width = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
808 edit_eol (edit, edit->curs1));
809 if (option_cursor_beyond_eol && curs_pos > line_width)
810 edit->over_col = curs_pos - line_width;
812 else
814 while (count < end_mark)
816 edit_delete (edit, 1);
817 count++;
821 edit_set_markers (edit, 0, 0, 0, 0);
822 edit->force |= REDRAW_PAGE;
823 return 0;
826 /* --------------------------------------------------------------------------------------------- */
828 static gboolean
829 editcmd_find (WEdit * edit, gsize * len)
831 off_t search_start = edit->search_start;
832 off_t search_end;
833 long start_mark = 0;
834 long end_mark = edit->last_byte;
835 int mark_res = 0;
837 if (edit_search_options.only_in_selection)
839 mark_res = eval_marks (edit, &start_mark, &end_mark);
840 if (mark_res != 0)
842 edit->search->error = MC_SEARCH_E_NOTFOUND;
843 edit->search->error_str = g_strdup (_("Search string not found"));
844 return FALSE;
846 if (edit_search_options.backwards)
848 if (search_start > end_mark || search_start <= start_mark)
850 search_start = end_mark;
853 else
855 if (search_start < start_mark || search_start >= end_mark)
857 search_start = start_mark;
861 else
863 if (edit_search_options.backwards)
864 end_mark = max (1, edit->curs1) - 1;
866 if (edit_search_options.backwards)
868 search_end = end_mark;
869 while ((int) search_start >= start_mark)
871 if (search_end > (off_t) (search_start + edit->search->original_len) &&
872 mc_search_is_fixed_search_str (edit->search))
874 search_end = search_start + edit->search->original_len;
876 if (mc_search_run (edit->search, (void *) edit, search_start, search_end, len)
877 && edit->search->normal_offset == search_start)
879 return TRUE;
881 search_start--;
883 edit->search->error_str = g_strdup (_("Search string not found"));
885 else
887 return mc_search_run (edit->search, (void *) edit, search_start, end_mark, len);
889 return FALSE;
892 /* --------------------------------------------------------------------------------------------- */
894 static char *
895 edit_replace_cmd__conv_to_display (char *str)
897 #ifdef HAVE_CHARSET
898 GString *tmp;
900 tmp = str_convert_to_display (str);
901 if (tmp != NULL)
903 if (tmp->len != 0)
904 return g_string_free (tmp, FALSE);
905 g_string_free (tmp, TRUE);
907 #endif
908 return g_strdup (str);
911 /* --------------------------------------------------------------------------------------------- */
913 static char *
914 edit_replace_cmd__conv_to_input (char *str)
916 #ifdef HAVE_CHARSET
917 GString *tmp;
919 tmp = str_convert_to_input (str);
920 if (tmp != NULL)
922 if (tmp->len != 0)
923 return g_string_free (tmp, FALSE);
924 g_string_free (tmp, TRUE);
926 #endif
927 return g_strdup (str);
930 /* --------------------------------------------------------------------------------------------- */
932 static void
933 edit_do_search (WEdit * edit)
935 gsize len = 0;
937 if (edit->search == NULL)
938 edit->search_start = edit->curs1;
940 edit_push_action (edit, KEY_PRESS + edit->start_display);
942 if (search_create_bookmark)
944 int found = 0, books = 0;
945 long l = 0, l_last = -1;
946 long q = 0;
948 search_create_bookmark = FALSE;
949 book_mark_flush (edit, -1);
951 while (TRUE)
953 if (!mc_search_run (edit->search, (void *) edit, q, edit->last_byte, &len))
954 break;
955 if (found == 0)
956 edit->search_start = edit->search->normal_offset;
957 found++;
958 l += edit_count_lines (edit, q, edit->search->normal_offset);
959 if (l != l_last)
961 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
962 books++;
964 l_last = l;
965 q = edit->search->normal_offset + 1;
968 if (found == 0)
969 edit_error_dialog (_("Search"), _("Search string not found"));
970 else
971 edit_cursor_move (edit, edit->search_start - edit->curs1);
973 else
975 if (edit->found_len != 0 && edit->search_start == edit->found_start + 1
976 && edit_search_options.backwards)
977 edit->search_start--;
979 if (edit->found_len != 0 && edit->search_start == edit->found_start - 1
980 && !edit_search_options.backwards)
981 edit->search_start++;
983 if (editcmd_find (edit, &len))
985 edit->found_start = edit->search_start = edit->search->normal_offset;
986 edit->found_len = len;
987 edit->over_col = 0;
988 edit_cursor_move (edit, edit->search_start - edit->curs1);
989 edit_scroll_screen_over_cursor (edit);
990 if (edit_search_options.backwards)
991 edit->search_start--;
992 else
993 edit->search_start++;
995 else
997 edit->search_start = edit->curs1;
998 if (edit->search->error_str != NULL)
999 edit_error_dialog (_("Search"), edit->search->error_str);
1003 edit->force |= REDRAW_COMPLETELY;
1004 edit_scroll_screen_over_cursor (edit);
1007 /* --------------------------------------------------------------------------------------------- */
1009 static void
1010 edit_search (WEdit *edit)
1012 if (editcmd_dialog_search_show (edit))
1013 edit_do_search (edit);
1016 /* --------------------------------------------------------------------------------------------- */
1017 /** Return a null terminated length of text. Result must be g_free'd */
1019 static unsigned char *
1020 edit_get_block (WEdit * edit, long start, long finish, int *l)
1022 unsigned char *s, *r;
1023 r = s = g_malloc0 (finish - start + 1);
1024 if (edit->column_highlight)
1026 *l = 0;
1027 /* copy from buffer, excluding chars that are out of the column 'margins' */
1028 while (start < finish)
1030 int c;
1031 long x;
1032 x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
1033 c = edit_get_byte (edit, start);
1034 if ((x >= edit->column1 && x < edit->column2)
1035 || (x >= edit->column2 && x < edit->column1) || c == '\n')
1037 *s++ = c;
1038 (*l)++;
1040 start++;
1043 else
1045 *l = finish - start;
1046 while (start < finish)
1047 *s++ = edit_get_byte (edit, start++);
1049 *s = 0;
1050 return r;
1053 /* --------------------------------------------------------------------------------------------- */
1054 /** copies a block to clipboard file */
1056 static int
1057 edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1059 int ret;
1060 gchar *tmp;
1061 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1062 ret = edit_save_block (edit, tmp, start, finish);
1063 g_free (tmp);
1064 return ret;
1067 /* --------------------------------------------------------------------------------------------- */
1069 static void
1070 pipe_mail (WEdit * edit, char *to, char *subject, char *cc)
1072 FILE *p = 0;
1073 char *s;
1075 to = name_quote (to, 0);
1076 subject = name_quote (subject, 0);
1077 cc = name_quote (cc, 0);
1078 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "", cc, " ", to, (char *) NULL);
1079 g_free (to);
1080 g_free (subject);
1081 g_free (cc);
1083 if (s)
1085 p = popen (s, "w");
1086 g_free (s);
1089 if (p)
1091 long i;
1092 for (i = 0; i < edit->last_byte; i++)
1093 fputc (edit_get_byte (edit, i), p);
1094 pclose (p);
1098 /* --------------------------------------------------------------------------------------------- */
1100 static gboolean
1101 is_break_char (char c)
1103 return (isspace (c) || strchr ("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
1106 /* --------------------------------------------------------------------------------------------- */
1107 /** find first character of current word */
1109 static int
1110 edit_find_word_start (WEdit * edit, long *word_start, gsize * word_len)
1112 int c, last;
1113 gsize i;
1115 /* return if at begin of file */
1116 if (edit->curs1 <= 0)
1117 return 0;
1119 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
1120 /* return if not at end or in word */
1121 if (is_break_char (c))
1122 return 0;
1124 /* search start of word to be completed */
1125 for (i = 2;; i++)
1127 /* return if at begin of file */
1128 if ((gsize) edit->curs1 < i)
1129 return 0;
1131 last = c;
1132 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
1134 if (is_break_char (c))
1136 /* return if word starts with digit */
1137 if (isdigit (last))
1138 return 0;
1140 *word_start = edit->curs1 - (i - 1); /* start found */
1141 *word_len = i - 1;
1142 break;
1145 /* success */
1146 return 1;
1149 /* --------------------------------------------------------------------------------------------- */
1151 * Get current word under cursor
1153 * @param edit editor object
1154 * @param srch mc_search object
1155 * @param word_start start word position
1157 * @return newly allocated string or NULL if no any words under cursor
1160 static char *
1161 edit_collect_completions_get_current_word (WEdit * edit, mc_search_t * srch, long word_start)
1163 gsize len = 0, i;
1164 GString *temp;
1166 if (!mc_search_run (srch, (void *) edit, word_start, edit->last_byte, &len))
1167 return NULL;
1169 temp = g_string_sized_new (len);
1171 for (i = 0; i < len; i++)
1173 int chr;
1175 chr = edit_get_byte (edit, word_start + i);
1176 if (!isspace (chr))
1177 g_string_append_c (temp, chr);
1180 return g_string_free (temp, temp->len == 0);
1183 /* --------------------------------------------------------------------------------------------- */
1184 /** collect the possible completions */
1186 static gsize
1187 edit_collect_completions (WEdit * edit, long word_start, gsize word_len,
1188 char *match_expr, struct selection *compl, gsize * num)
1190 gsize len = 0;
1191 gsize max_len = 0;
1192 gsize i;
1193 int skip;
1194 GString *temp;
1195 mc_search_t *srch;
1196 long last_byte, start = -1;
1197 char *current_word;
1199 srch = mc_search_new (match_expr, -1);
1200 if (srch == NULL)
1201 return 0;
1203 if (mc_config_get_bool
1204 (mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0))
1206 last_byte = edit->last_byte;
1208 else
1210 last_byte = word_start;
1213 srch->search_type = MC_SEARCH_T_REGEX;
1214 srch->is_case_sensitive = TRUE;
1215 srch->search_fn = edit_search_cmd_callback;
1217 current_word = edit_collect_completions_get_current_word (edit, srch, word_start);
1219 temp = g_string_new ("");
1221 /* collect max MAX_WORD_COMPLETIONS completions */
1222 while (mc_search_run (srch, (void *) edit, start + 1, last_byte, &len))
1224 g_string_set_size (temp, 0);
1225 start = srch->normal_offset;
1227 /* add matched completion if not yet added */
1228 for (i = 0; i < len; i++)
1230 skip = edit_get_byte (edit, start + i);
1231 if (isspace (skip))
1232 continue;
1234 /* skip current word */
1235 if (start + (long) i == word_start)
1236 break;
1238 g_string_append_c (temp, skip);
1241 if (temp->len == 0)
1242 continue;
1244 if (current_word != NULL && strcmp (current_word, temp->str) == 0)
1245 continue;
1247 skip = 0;
1249 for (i = 0; i < *num; i++)
1251 if (strncmp
1252 ((char *) &compl[i].text[word_len],
1253 (char *) &temp->str[word_len], max (len, compl[i].len) - word_len) == 0)
1255 struct selection this = compl[i];
1256 for (++i; i < *num; i++)
1258 compl[i - 1] = compl[i];
1260 compl[*num - 1] = this;
1261 skip = 1;
1262 break; /* skip it, already added */
1265 if (skip != 0)
1266 continue;
1268 if (*num == MAX_WORD_COMPLETIONS)
1270 g_free (compl[0].text);
1271 for (i = 1; i < *num; i++)
1273 compl[i - 1] = compl[i];
1275 (*num)--;
1277 #ifdef HAVE_CHARSET
1279 GString *recoded;
1280 recoded = str_convert_to_display (temp->str);
1282 if (recoded && recoded->len)
1283 g_string_assign (temp, recoded->str);
1285 g_string_free (recoded, TRUE);
1287 #endif
1288 compl[*num].text = g_strdup (temp->str);
1289 compl[*num].len = temp->len;
1290 (*num)++;
1291 start += len;
1293 /* note the maximal length needed for the completion dialog */
1294 if (len > max_len)
1295 max_len = len;
1298 mc_search_free (srch);
1299 g_string_free (temp, TRUE);
1300 g_free (current_word);
1302 return max_len;
1306 /* --------------------------------------------------------------------------------------------- */
1307 /*** public functions ****************************************************************************/
1308 /* --------------------------------------------------------------------------------------------- */
1310 void
1311 edit_help_cmd (WEdit * edit)
1313 interactive_display (NULL, "[Internal File Editor]");
1314 edit->force |= REDRAW_COMPLETELY;
1317 /* --------------------------------------------------------------------------------------------- */
1319 void
1320 edit_refresh_cmd (WEdit * edit)
1322 #ifdef HAVE_SLANG
1323 int color;
1325 edit_get_syntax_color (edit, -1, &color);
1326 tty_touch_screen ();
1327 mc_refresh ();
1328 #else
1329 (void) edit;
1331 clr_scr ();
1332 repaint_screen ();
1333 #endif /* !HAVE_SLANG */
1334 tty_keypad (TRUE);
1337 /* --------------------------------------------------------------------------------------------- */
1339 void
1340 menu_save_mode_cmd (void)
1342 /* diaog sizes */
1343 const int DLG_X = 38;
1344 const int DLG_Y = 13;
1346 char *str_result;
1348 const char *str[] = {
1349 N_("&Quick save"),
1350 N_("&Safe save"),
1351 N_("&Do backups with following extension:")
1354 QuickWidget widgets[] = {
1355 /* 0 */
1356 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
1357 /* 1 */
1358 QUICK_BUTTON (6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
1359 /* 2 */
1360 QUICK_CHECKBOX (4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
1361 /* 3 */
1362 QUICK_INPUT (8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
1363 /* 4 */
1364 QUICK_RADIO (4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
1365 QUICK_END
1368 QuickDialog dialog = {
1369 DLG_X, DLG_Y, -1, -1, N_("Edit Save Mode"),
1370 "[Edit Save Mode]", widgets, NULL, FALSE
1373 size_t i;
1374 size_t maxlen = 0;
1375 size_t w0, w1, b_len, w3;
1377 assert (option_backup_ext != NULL);
1379 /* OK/Cancel buttons */
1380 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
1381 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
1382 b_len = w0 + w1 + 3;
1384 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
1386 w3 = 0;
1387 for (i = 0; i < 3; i++)
1389 #ifdef ENABLE_NLS
1390 str[i] = _(str[i]);
1391 #endif
1392 w3 = max (w3, (size_t) str_term_width1 (str[i]));
1395 maxlen = max (maxlen, w3 + 4);
1397 dialog.xlen = min ((size_t) COLS, maxlen + 8);
1399 widgets[3].u.input.len = w3;
1400 widgets[1].relative_x = (dialog.xlen - b_len) / 2;
1401 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
1403 for (i = 0; i < sizeof (widgets) / sizeof (widgets[0]); i++)
1404 widgets[i].x_divisions = dialog.xlen;
1406 if (quick_dialog (&dialog) != B_CANCEL)
1408 g_free (option_backup_ext);
1409 option_backup_ext = str_result;
1413 /* --------------------------------------------------------------------------------------------- */
1415 void
1416 edit_set_filename (WEdit * edit, const char *name)
1418 g_free (edit->filename);
1420 if (name == NULL)
1421 name = "";
1423 edit->filename = tilde_expand (name);
1424 if (edit->dir == NULL && !g_path_is_absolute (name))
1425 edit->dir = g_strdup (vfs_get_current_dir ());
1428 /* --------------------------------------------------------------------------------------------- */
1429 /* Here we want to warn the users of overwriting an existing file,
1430 but only if they have made a change to the filename */
1431 /* returns 1 on success */
1433 edit_save_as_cmd (WEdit * edit)
1435 /* This heads the 'Save As' dialog box */
1436 char *exp;
1437 int save_lock = 0;
1438 int different_filename = 0;
1440 if (!edit_check_newline (edit))
1441 return 0;
1443 exp = edit_get_save_file_as (edit);
1444 edit_push_action (edit, KEY_PRESS + edit->start_display);
1446 if (exp)
1448 if (!*exp)
1450 g_free (exp);
1451 edit->force |= REDRAW_COMPLETELY;
1452 return 0;
1454 else
1456 int rv;
1457 if (strcmp (edit->filename, exp))
1459 int file;
1460 different_filename = 1;
1461 file = mc_open (exp, O_RDONLY | O_BINARY);
1462 if (file != -1)
1464 /* the file exists */
1465 mc_close (file);
1466 /* Overwrite the current file or cancel the operation */
1467 if (edit_query_dialog2
1468 (_("Warning"),
1469 _("A file already exists with this name"), _("&Overwrite"), _("&Cancel")))
1471 edit->force |= REDRAW_COMPLETELY;
1472 g_free (exp);
1473 return 0;
1476 else
1478 edit->stat1.st_mode |= S_IWUSR;
1480 save_lock = lock_file (exp);
1482 else
1484 /* filenames equal, check if already locked */
1485 if (!edit->locked && !edit->delete_file)
1486 save_lock = lock_file (exp);
1489 if (different_filename)
1492 * Allow user to write into saved (under another name) file
1493 * even if original file had r/o user permissions.
1495 edit->stat1.st_mode |= S_IWRITE;
1498 rv = edit_save_file (edit, exp);
1499 switch (rv)
1501 case 1:
1502 /* Succesful, so unlock both files */
1503 if (different_filename)
1505 if (save_lock)
1506 unlock_file (exp);
1507 if (edit->locked)
1508 edit->locked = edit_unlock_file (edit);
1510 else
1512 if (edit->locked || save_lock)
1513 edit->locked = edit_unlock_file (edit);
1516 edit_set_filename (edit, exp);
1517 if (edit->lb != LB_ASIS)
1518 edit_reload (edit, exp);
1519 g_free (exp);
1520 edit->modified = 0;
1521 edit->delete_file = 0;
1522 if (different_filename)
1523 edit_load_syntax (edit, NULL, edit->syntax_type);
1524 edit->force |= REDRAW_COMPLETELY;
1525 return 1;
1526 default:
1527 edit_error_dialog (_("Save as"), get_sys_error (_("Cannot save file")));
1528 /* fallthrough */
1529 case -1:
1530 /* Failed, so maintain modify (not save) lock */
1531 if (save_lock)
1532 unlock_file (exp);
1533 g_free (exp);
1534 edit->force |= REDRAW_COMPLETELY;
1535 return 0;
1539 edit->force |= REDRAW_COMPLETELY;
1540 return 0;
1543 /* {{{ Macro stuff starts here */
1546 /* --------------------------------------------------------------------------------------------- */
1547 /** returns 0 on error */
1550 edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
1552 FILE *f;
1553 int s, i;
1555 edit_push_action (edit, KEY_PRESS + edit->start_display);
1556 s = editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), 1);
1557 edit->force |= REDRAW_COMPLETELY;
1558 if (s)
1560 if (edit_delete_macro (edit, s))
1561 return 0;
1562 f = edit_open_macro_file ("a+");
1563 if (f)
1565 fprintf (f, ("key '%d 0': "), s);
1566 for (i = 0; i < n; i++)
1567 fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
1568 fprintf (f, ";\n");
1569 fclose (f);
1570 if (saved_macros_loaded)
1572 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
1573 saved_macro[i] = s;
1575 return 1;
1577 else
1578 edit_error_dialog (_("Save macro"), get_sys_error (_("Cannot open macro file")));
1580 return 0;
1583 /* --------------------------------------------------------------------------------------------- */
1585 void
1586 edit_delete_macro_cmd (WEdit * edit)
1588 int command;
1590 command = editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), 1);
1592 if (command != 0)
1593 edit_delete_macro (edit, command);
1596 /* --------------------------------------------------------------------------------------------- */
1597 /** return 0 on error */
1600 edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
1602 FILE *f;
1603 int s, i = 0, found = 0;
1605 (void) edit;
1607 if (saved_macros_loaded)
1608 if (macro_exists (k) < 0)
1609 return 0;
1611 f = edit_open_macro_file ("r");
1612 if (f != NULL)
1614 struct macro dummy;
1617 int u;
1618 u = fscanf (f, ("key '%d 0': "), &s);
1619 if (!u || u == EOF)
1620 break;
1621 if (!saved_macros_loaded)
1622 saved_macro[i++] = s;
1623 if (!found)
1625 *n = 0;
1626 while (*n < MAX_MACRO_LENGTH
1627 && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
1628 (*n)++;
1630 else
1632 while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
1635 int ret;
1636 ret = fscanf (f, ";\n");
1638 if (s == k)
1639 found = 1;
1641 while (!found || !saved_macros_loaded);
1642 if (!saved_macros_loaded)
1644 saved_macro[i] = 0;
1645 saved_macros_loaded = 1;
1647 fclose (f);
1648 return found;
1650 else
1651 edit_error_dialog (_("Load macro"), get_sys_error (_("Cannot open macro file")));
1652 return 0;
1655 /* }}} Macro stuff starts here */
1657 /* --------------------------------------------------------------------------------------------- */
1658 /** returns 1 on success */
1661 edit_save_confirm_cmd (WEdit * edit)
1663 gchar *f = NULL;
1665 if (!edit_check_newline (edit))
1666 return 0;
1668 if (edit_confirm_save)
1670 f = g_strdup_printf (_("Confirm save file: \"%s\""), edit->filename);
1671 if (edit_query_dialog2 (_("Save file"), f, _("&Save"), _("&Cancel")))
1673 g_free (f);
1674 return 0;
1676 g_free (f);
1678 return edit_save_cmd (edit);
1682 /* --------------------------------------------------------------------------------------------- */
1683 /** returns 1 on success */
1686 edit_new_cmd (WEdit * edit)
1688 if (edit->modified)
1690 if (edit_query_dialog2
1691 (_("Warning"),
1693 ("Current text was modified without a file save.\nContinue discards these changes"),
1694 _("C&ontinue"), _("&Cancel")))
1696 edit->force |= REDRAW_COMPLETELY;
1697 return 0;
1700 edit->force |= REDRAW_COMPLETELY;
1702 return edit_renew (edit); /* if this gives an error, something has really screwed up */
1705 /* --------------------------------------------------------------------------------------------- */
1708 edit_load_cmd (WEdit * edit, edit_current_file_t what)
1710 char *exp;
1712 if (edit->modified
1713 && (edit_query_dialog2
1714 (_("Warning"),
1715 _("Current text was modified without a file save.\n"
1716 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")) == 1))
1718 edit->force |= REDRAW_COMPLETELY;
1719 return 0;
1722 switch (what)
1724 case EDIT_FILE_COMMON:
1725 exp = input_expand_dialog (_("Load"), _("Enter file name:"),
1726 MC_HISTORY_EDIT_LOAD, edit->filename);
1728 if (exp)
1730 if (*exp)
1731 edit_load_file_from_filename (edit, exp);
1732 g_free (exp);
1734 break;
1736 case EDIT_FILE_SYNTAX:
1737 edit_load_syntax_file (edit);
1738 break;
1740 case EDIT_FILE_MENU:
1741 edit_load_menu_file (edit);
1742 break;
1744 default:
1745 break;
1748 edit->force |= REDRAW_COMPLETELY;
1749 return 0;
1752 /* --------------------------------------------------------------------------------------------- */
1754 if mark2 is -1 then marking is from mark1 to the cursor.
1755 Otherwise its between the markers. This handles this.
1756 Returns 1 if no text is marked.
1760 eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1762 if (edit->mark1 != edit->mark2)
1764 long start_bol, start_eol;
1765 long end_bol, end_eol;
1766 long col1, col2;
1767 long diff1, diff2;
1768 long end_mark_curs;
1770 if (edit->end_mark_curs < 0)
1771 end_mark_curs = edit->curs1;
1772 else
1773 end_mark_curs = edit->end_mark_curs;
1775 if (edit->mark2 >= 0)
1777 *start_mark = min (edit->mark1, edit->mark2);
1778 *end_mark = max (edit->mark1, edit->mark2);
1780 else
1782 *start_mark = min (edit->mark1, end_mark_curs);
1783 *end_mark = max (edit->mark1, end_mark_curs);
1784 edit->column2 = edit->curs_col + edit->over_col;
1787 if (edit->column_highlight
1788 && (((edit->mark1 > end_mark_curs) && (edit->column1 < edit->column2))
1789 || ((edit->mark1 < end_mark_curs) && (edit->column1 > edit->column2))))
1791 start_bol = edit_bol (edit, *start_mark);
1792 start_eol = edit_eol (edit, start_bol - 1) + 1;
1793 end_bol = edit_bol (edit, *end_mark);
1794 end_eol = edit_eol (edit, *end_mark);
1795 col1 = min (edit->column1, edit->column2);
1796 col2 = max (edit->column1, edit->column2);
1798 diff1 =
1799 edit_move_forward3 (edit, start_bol, col2, 0) - edit_move_forward3 (edit, start_bol,
1800 col1, 0);
1801 diff2 =
1802 edit_move_forward3 (edit, end_bol, col2, 0) - edit_move_forward3 (edit, end_bol,
1803 col1, 0);
1805 *start_mark -= diff1;
1806 *end_mark += diff2;
1807 *start_mark = max (*start_mark, start_eol);
1808 *end_mark = min (*end_mark, end_eol);
1810 return 0;
1812 else
1814 *start_mark = *end_mark = 0;
1815 edit->column2 = edit->column1 = 0;
1816 return 1;
1820 /* --------------------------------------------------------------------------------------------- */
1822 void
1823 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1825 long cursor;
1826 int i, col;
1827 cursor = edit->curs1;
1828 col = edit_get_col (edit);
1829 for (i = 0; i < size; i++)
1831 if (data[i] == '\n')
1832 { /* fill in and move to next line */
1833 int l;
1834 long p;
1835 if (edit_get_byte (edit, edit->curs1) != '\n')
1837 l = width - (edit_get_col (edit) - col);
1838 while (l > 0)
1840 edit_insert (edit, ' ');
1841 l -= space_width;
1844 for (p = edit->curs1;; p++)
1846 if (p == edit->last_byte)
1848 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1849 edit_insert_ahead (edit, '\n');
1850 p++;
1851 break;
1853 if (edit_get_byte (edit, p) == '\n')
1855 p++;
1856 break;
1859 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1860 l = col - edit_get_col (edit);
1861 while (l >= space_width)
1863 edit_insert (edit, ' ');
1864 l -= space_width;
1866 continue;
1868 edit_insert (edit, data[i]);
1870 edit_cursor_move (edit, cursor - edit->curs1);
1873 /* --------------------------------------------------------------------------------------------- */
1876 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1878 long cursor;
1879 int i, col;
1880 int blocklen = -1, width;
1881 unsigned char *data;
1882 cursor = edit->curs1;
1883 col = edit_get_col (edit);
1884 data = g_malloc0 (TEMP_BUF_LEN);
1885 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0)
1887 for (width = 0; width < blocklen; width++)
1889 if (data[width] == '\n')
1890 break;
1892 for (i = 0; i < blocklen; i++)
1894 if (data[i] == '\n')
1895 { /* fill in and move to next line */
1896 int l;
1897 long p;
1898 if (edit_get_byte (edit, edit->curs1) != '\n')
1900 l = width - (edit_get_col (edit) - col);
1901 while (l > 0)
1903 edit_insert (edit, ' ');
1904 l -= space_width;
1907 for (p = edit->curs1;; p++)
1909 if (p == edit->last_byte)
1911 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1912 edit_insert_ahead (edit, '\n');
1913 p++;
1914 break;
1916 if (edit_get_byte (edit, p) == '\n')
1918 p++;
1919 break;
1922 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1923 l = col - edit_get_col (edit);
1924 while (l >= space_width)
1926 edit_insert (edit, ' ');
1927 l -= space_width;
1929 continue;
1931 edit_insert (edit, data[i]);
1934 edit_cursor_move (edit, cursor - edit->curs1);
1935 g_free (data);
1936 edit->force |= REDRAW_PAGE;
1937 return blocklen;
1940 /* --------------------------------------------------------------------------------------------- */
1942 void
1943 edit_block_copy_cmd (WEdit * edit)
1945 long start_mark, end_mark, current = edit->curs1;
1946 int size;
1947 unsigned char *copy_buf;
1949 edit_update_curs_col (edit);
1950 if (eval_marks (edit, &start_mark, &end_mark))
1951 return;
1953 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1955 /* all that gets pushed are deletes hence little space is used on the stack */
1957 edit_push_markers (edit);
1959 if (edit->column_highlight)
1961 edit_insert_column_of_text (edit, copy_buf, size, abs (edit->column2 - edit->column1));
1963 else
1965 while (size--)
1966 edit_insert_ahead (edit, copy_buf[size]);
1969 g_free (copy_buf);
1970 edit_scroll_screen_over_cursor (edit);
1972 if (edit->column_highlight)
1974 edit_set_markers (edit, 0, 0, 0, 0);
1975 edit_push_action (edit, COLUMN_ON);
1976 edit->column_highlight = 0;
1978 else if (start_mark < current && end_mark > current)
1979 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1981 edit->force |= REDRAW_PAGE;
1985 /* --------------------------------------------------------------------------------------------- */
1987 void
1988 edit_block_move_cmd (WEdit * edit)
1990 long count;
1991 long current;
1992 unsigned char *copy_buf;
1993 long start_mark, end_mark;
1994 int deleted = 0;
1995 int x = 0;
1997 if (eval_marks (edit, &start_mark, &end_mark))
1998 return;
1999 if (edit->column_highlight)
2001 edit_update_curs_col (edit);
2002 x = edit->curs_col;
2003 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
2004 if ((x > edit->column1 && x < edit->column2)
2005 || (x > edit->column2 && x < edit->column1))
2006 return;
2008 else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
2009 return;
2011 if ((end_mark - start_mark) > option_max_undo / 2)
2012 if (edit_query_dialog2
2013 (_("Warning"),
2015 ("Block is large, you may not be able to undo this action"),
2016 _("C&ontinue"), _("&Cancel")))
2017 return;
2019 edit_push_markers (edit);
2020 current = edit->curs1;
2021 if (edit->column_highlight)
2023 long line;
2024 int size, c1, c2;
2025 line = edit->curs_line;
2026 if (edit->mark2 < 0)
2027 edit_mark_cmd (edit, 0);
2028 c1 = min (edit->column1, edit->column2);
2029 c2 = max (edit->column1, edit->column2);
2030 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
2031 if (x < c2)
2033 edit_block_delete_cmd (edit);
2034 deleted = 1;
2036 edit_move_to_line (edit, line);
2037 edit_cursor_move (edit,
2038 edit_move_forward3 (edit,
2039 edit_bol (edit, edit->curs1), x, 0) - edit->curs1);
2040 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
2041 if (!deleted)
2043 line = edit->curs_line;
2044 edit_update_curs_col (edit);
2045 x = edit->curs_col;
2046 edit_block_delete_cmd (edit);
2047 edit_move_to_line (edit, line);
2048 edit_cursor_move (edit,
2049 edit_move_forward3 (edit,
2050 edit_bol (edit,
2051 edit->curs1), x, 0) - edit->curs1);
2053 edit_set_markers (edit, 0, 0, 0, 0);
2054 edit_push_action (edit, COLUMN_ON);
2055 edit->column_highlight = 0;
2057 else
2059 copy_buf = g_malloc0 (end_mark - start_mark);
2060 edit_cursor_move (edit, start_mark - edit->curs1);
2061 edit_scroll_screen_over_cursor (edit);
2062 count = start_mark;
2063 while (count < end_mark)
2065 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
2066 count++;
2068 edit_scroll_screen_over_cursor (edit);
2069 edit_cursor_move (edit,
2070 current - edit->curs1 -
2071 (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
2072 edit_scroll_screen_over_cursor (edit);
2073 while (count-- > start_mark)
2074 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
2075 edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
2077 edit_scroll_screen_over_cursor (edit);
2078 g_free (copy_buf);
2079 edit->force |= REDRAW_PAGE;
2082 /* --------------------------------------------------------------------------------------------- */
2083 /** returns 1 if canceelled by user */
2086 edit_block_delete_cmd (WEdit * edit)
2088 long start_mark, end_mark;
2089 if (eval_marks (edit, &start_mark, &end_mark))
2091 edit_delete_line (edit);
2092 return 0;
2094 return edit_block_delete (edit);
2097 /* --------------------------------------------------------------------------------------------- */
2098 /** call with edit = 0 before shutdown to close memory leaks */
2100 void
2101 edit_replace_cmd (WEdit * edit, int again)
2103 /* 1 = search string, 2 = replace with */
2104 static char *saved1 = NULL; /* saved default[123] */
2105 static char *saved2 = NULL;
2106 char *input1 = NULL; /* user input from the dialog */
2107 char *input2 = NULL;
2108 char *disp1 = NULL;
2109 char *disp2 = NULL;
2110 long times_replaced = 0;
2111 gboolean once_found = FALSE;
2113 if (!edit)
2115 g_free (saved1), saved1 = NULL;
2116 g_free (saved2), saved2 = NULL;
2117 return;
2120 edit->force |= REDRAW_COMPLETELY;
2122 if (again && !saved1 && !saved2)
2123 again = 0;
2125 if (again)
2127 input1 = g_strdup (saved1 ? saved1 : "");
2128 input2 = g_strdup (saved2 ? saved2 : "");
2130 else
2132 char *tmp_inp1, *tmp_inp2;
2133 disp1 = edit_replace_cmd__conv_to_display (saved1 ? saved1 : (char *) "");
2134 disp2 = edit_replace_cmd__conv_to_display (saved2 ? saved2 : (char *) "");
2136 edit_push_action (edit, KEY_PRESS + edit->start_display);
2138 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2);
2140 g_free (disp1);
2141 g_free (disp2);
2143 if (input1 == NULL || *input1 == '\0')
2145 edit->force = REDRAW_COMPLETELY;
2146 goto cleanup;
2149 tmp_inp1 = input1;
2150 tmp_inp2 = input2;
2151 input1 = edit_replace_cmd__conv_to_input (input1);
2152 input2 = edit_replace_cmd__conv_to_input (input2);
2153 g_free (tmp_inp1);
2154 g_free (tmp_inp2);
2156 g_free (saved1), saved1 = g_strdup (input1);
2157 g_free (saved2), saved2 = g_strdup (input2);
2159 mc_search_free (edit->search);
2160 edit->search = NULL;
2163 if (!edit->search)
2165 edit->search = mc_search_new (input1, -1);
2166 if (edit->search == NULL)
2168 edit->search_start = edit->curs1;
2169 goto cleanup;
2171 edit->search->search_type = edit_search_options.type;
2172 edit->search->is_all_charsets = edit_search_options.all_codepages;
2173 edit->search->is_case_sensitive = edit_search_options.case_sens;
2174 edit->search->whole_words = edit_search_options.whole_words;
2175 edit->search->search_fn = edit_search_cmd_callback;
2178 if (edit->found_len && edit->search_start == edit->found_start + 1
2179 && edit_search_options.backwards)
2180 edit->search_start--;
2182 if (edit->found_len && edit->search_start == edit->found_start - 1
2183 && !edit_search_options.backwards)
2184 edit->search_start++;
2188 gsize len = 0;
2190 if (!editcmd_find (edit, &len))
2192 if (!(edit->search->error == MC_SEARCH_E_OK ||
2193 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
2195 edit_error_dialog (_("Search"), edit->search->error_str);
2197 break;
2199 once_found = TRUE;
2201 edit->search_start = edit->search->normal_offset;
2202 /*returns negative on not found or error in pattern */
2204 if ((edit->search_start >= 0) && (edit->search_start < edit->last_byte))
2206 gsize i;
2207 GString *tmp_str, *repl_str;
2209 edit->found_start = edit->search_start;
2210 i = edit->found_len = len;
2212 edit_cursor_move (edit, edit->search_start - edit->curs1);
2213 edit_scroll_screen_over_cursor (edit);
2215 if (edit->replace_mode == 0)
2217 int l;
2218 int prompt;
2220 l = edit->curs_row - edit->widget.lines / 3;
2221 if (l > 0)
2222 edit_scroll_downward (edit, l);
2223 if (l < 0)
2224 edit_scroll_upward (edit, -l);
2226 edit_scroll_screen_over_cursor (edit);
2227 edit->force |= REDRAW_PAGE;
2228 edit_render_keypress (edit);
2230 /*so that undo stops at each query */
2231 edit_push_key_press (edit);
2232 /* and prompt 2/3 down */
2233 disp1 = edit_replace_cmd__conv_to_display (saved1);
2234 disp2 = edit_replace_cmd__conv_to_display (saved2);
2235 prompt = editcmd_dialog_replace_prompt_show (edit, disp1, disp2, -1, -1);
2236 g_free (disp1);
2237 g_free (disp2);
2239 if (prompt == B_REPLACE_ALL)
2240 edit->replace_mode = 1;
2241 else if (prompt == B_SKIP_REPLACE)
2243 if (edit_search_options.backwards)
2244 edit->search_start--;
2245 else
2246 edit->search_start++;
2247 continue; /* loop */
2249 else if (prompt == B_CANCEL)
2251 edit->replace_mode = -1;
2252 break; /* loop */
2256 /* don't process string each time */
2257 tmp_str = g_string_new (input2);
2258 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
2259 g_string_free (tmp_str, TRUE);
2261 if (edit->search->error != MC_SEARCH_E_OK)
2263 edit_error_dialog (_("Replace"), edit->search->error_str);
2264 g_string_free (repl_str, TRUE);
2265 break;
2268 /* delete then insert new */
2269 for (i = 0; i < len; i++)
2270 edit_delete (edit, 1);
2272 for (i = 0; i < repl_str->len; i++)
2273 edit_insert (edit, repl_str->str[i]);
2275 edit->found_len = repl_str->len;
2276 g_string_free (repl_str, TRUE);
2277 times_replaced++;
2279 /* so that we don't find the same string again */
2280 if (edit_search_options.backwards)
2281 edit->search_start--;
2282 else
2284 edit->search_start += edit->found_len;
2286 if (edit->search_start >= edit->last_byte)
2287 break;
2290 edit_scroll_screen_over_cursor (edit);
2292 else
2294 /* try and find from right here for next search */
2295 edit->search_start = edit->curs1;
2296 edit_update_curs_col (edit);
2298 edit->force |= REDRAW_PAGE;
2299 edit_render_keypress (edit);
2301 if (times_replaced == 0)
2302 query_dialog (_("Replace"), _("Search string not found"), D_NORMAL, 1, _("&OK"));
2303 break;
2306 while (edit->replace_mode >= 0);
2308 edit_scroll_screen_over_cursor (edit);
2309 edit->force |= REDRAW_COMPLETELY;
2310 edit_render_keypress (edit);
2312 if ((edit->replace_mode == 1) && (times_replaced != 0))
2313 message (D_NORMAL, _("Replace"), _("%ld replacements made"), times_replaced);
2315 cleanup:
2316 g_free (input1);
2317 g_free (input2);
2320 /* --------------------------------------------------------------------------------------------- */
2323 edit_search_cmd_callback (const void *user_data, gsize char_offset)
2325 return edit_get_byte ((WEdit *) user_data, (long) char_offset);
2328 /* --------------------------------------------------------------------------------------------- */
2330 void
2331 edit_search_cmd (WEdit * edit, gboolean again)
2333 if (edit == NULL)
2334 return;
2336 if (!again)
2337 edit_search (edit);
2338 else if (edit->last_search_string != NULL)
2339 edit_do_search (edit);
2340 else
2342 /* find last search string in history */
2343 GList *history;
2345 history = history_get (MC_HISTORY_SHARED_SEARCH);
2346 if (history != NULL && history->data != NULL)
2348 edit->last_search_string = (char *) history->data;
2349 history->data = NULL;
2350 history = g_list_first (history);
2351 g_list_foreach (history, (GFunc) g_free, NULL);
2352 g_list_free (history);
2354 edit->search = mc_search_new (edit->last_search_string, -1);
2355 if (edit->search == NULL)
2357 /* if not... then ask for an expression */
2358 g_free (edit->last_search_string);
2359 edit->last_search_string = NULL;
2360 edit_search (edit);
2362 else
2364 edit->search->search_type = edit_search_options.type;
2365 edit->search->is_all_charsets = edit_search_options.all_codepages;
2366 edit->search->is_case_sensitive = edit_search_options.case_sens;
2367 edit->search->whole_words = edit_search_options.whole_words;
2368 edit->search->search_fn = edit_search_cmd_callback;
2369 edit_do_search (edit);
2372 else
2374 /* if not... then ask for an expression */
2375 g_free (edit->last_search_string);
2376 edit->last_search_string = NULL;
2377 edit_search (edit);
2383 /* --------------------------------------------------------------------------------------------- */
2385 * Check if it's OK to close the editor. If there are unsaved changes,
2386 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
2389 gboolean
2390 edit_ok_to_exit (WEdit * edit)
2392 int act;
2394 if (!edit->modified)
2395 return TRUE;
2397 if (!midnight_shutdown)
2399 if (!edit_check_newline (edit))
2400 return FALSE;
2402 query_set_sel (2);
2403 act = edit_query_dialog3 (_("Quit"), _("File was modified. Save with exit?"),
2404 _("&Yes"), _("&No"), _("&Cancel quit"));
2406 else
2408 act =
2409 edit_query_dialog2 (_("Quit"),
2410 _("Midnight Commander is being shut down.\nSave modified file?"),
2411 _("&Yes"), _("&No"));
2413 /* Esc is No */
2414 if (act == -1)
2415 act = 1;
2418 switch (act)
2420 case 0: /* Yes */
2421 edit_push_markers (edit);
2422 edit_set_markers (edit, 0, 0, 0, 0);
2423 if (!edit_save_cmd (edit) || midnight_shutdown)
2424 return (gboolean) midnight_shutdown;
2425 break;
2426 case 1: /* No */
2427 break;
2428 case 2: /* Cancel quit */
2429 case -1: /* Esc */
2430 return FALSE;
2433 return TRUE;
2436 /* --------------------------------------------------------------------------------------------- */
2437 /** save block, returns 1 on success */
2440 edit_save_block (WEdit * edit, const char *filename, long start, long finish)
2442 int len, file;
2444 file = mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
2445 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY);
2446 if (file == -1)
2447 return 0;
2449 if (edit->column_highlight)
2451 int r;
2452 r = mc_write (file, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC));
2453 if (r > 0)
2455 unsigned char *block, *p;
2456 p = block = edit_get_block (edit, start, finish, &len);
2457 while (len)
2459 r = mc_write (file, p, len);
2460 if (r < 0)
2461 break;
2462 p += r;
2463 len -= r;
2465 g_free (block);
2468 else
2470 unsigned char *buf;
2471 int i = start, end;
2472 len = finish - start;
2473 buf = g_malloc0 (TEMP_BUF_LEN);
2474 while (start != finish)
2476 end = min (finish, start + TEMP_BUF_LEN);
2477 for (; i < end; i++)
2478 buf[i - start] = edit_get_byte (edit, i);
2479 len -= mc_write (file, (char *) buf, end - start);
2480 start = end;
2482 g_free (buf);
2484 mc_close (file);
2485 if (len)
2486 return 0;
2487 return 1;
2490 /* --------------------------------------------------------------------------------------------- */
2492 void
2493 edit_paste_from_history (WEdit * edit)
2495 (void) edit;
2496 edit_error_dialog (_("Error"), _("This function is not implemented"));
2499 /* --------------------------------------------------------------------------------------------- */
2502 edit_copy_to_X_buf_cmd (WEdit * edit)
2504 long start_mark, end_mark;
2505 if (eval_marks (edit, &start_mark, &end_mark))
2506 return 0;
2507 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2509 edit_error_dialog (_("Copy to clipboard"), get_sys_error (_("Unable to save to file")));
2510 return 1;
2512 /* try use external clipboard utility */
2513 copy_file_to_ext_clip ();
2515 return 0;
2518 /* --------------------------------------------------------------------------------------------- */
2521 edit_cut_to_X_buf_cmd (WEdit * edit)
2523 long start_mark, end_mark;
2524 if (eval_marks (edit, &start_mark, &end_mark))
2525 return 0;
2526 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
2528 edit_error_dialog (_("Cut to clipboard"), _("Unable to save to file"));
2529 return 1;
2531 /* try use external clipboard utility */
2532 copy_file_to_ext_clip ();
2534 edit_block_delete_cmd (edit);
2535 edit_mark_cmd (edit, 1);
2536 return 0;
2539 /* --------------------------------------------------------------------------------------------- */
2541 void
2542 edit_paste_from_X_buf_cmd (WEdit * edit)
2544 gchar *tmp;
2545 /* try use external clipboard utility */
2546 paste_to_file_from_ext_clip ();
2547 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2548 edit_insert_file (edit, tmp);
2549 g_free (tmp);
2553 /* --------------------------------------------------------------------------------------------- */
2555 * Ask user for the line and go to that line.
2556 * Negative numbers mean line from the end (i.e. -1 is the last line).
2559 void
2560 edit_goto_cmd (WEdit * edit)
2562 char *f;
2563 static long line = 0; /* line as typed, saved as default */
2564 long l;
2565 char *error;
2566 char s[32];
2568 g_snprintf (s, sizeof (s), "%ld", line);
2569 f = input_dialog (_("Goto line"), _("Enter line:"), MC_HISTORY_EDIT_GOTO_LINE, line ? s : "");
2570 if (!f)
2571 return;
2573 if (!*f)
2575 g_free (f);
2576 return;
2579 l = strtol (f, &error, 0);
2580 if (*error)
2582 g_free (f);
2583 return;
2586 line = l;
2587 if (l < 0)
2588 l = edit->total_lines + l + 2;
2589 edit_move_display (edit, l - edit->widget.lines / 2 - 1);
2590 edit_move_to_line (edit, l - 1);
2591 edit->force |= REDRAW_COMPLETELY;
2592 g_free (f);
2596 /* --------------------------------------------------------------------------------------------- */
2597 /** Return 1 on success */
2600 edit_save_block_cmd (WEdit * edit)
2602 long start_mark, end_mark;
2603 char *exp, *tmp;
2605 if (eval_marks (edit, &start_mark, &end_mark))
2606 return 1;
2608 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2609 exp =
2610 input_expand_dialog (_("Save block"), _("Enter file name:"),
2611 MC_HISTORY_EDIT_SAVE_BLOCK, tmp);
2612 g_free (tmp);
2613 edit_push_action (edit, KEY_PRESS + edit->start_display);
2614 if (exp)
2616 if (!*exp)
2618 g_free (exp);
2619 return 0;
2621 else
2623 if (edit_save_block (edit, exp, start_mark, end_mark))
2625 g_free (exp);
2626 edit->force |= REDRAW_COMPLETELY;
2627 return 1;
2629 else
2631 g_free (exp);
2632 edit_error_dialog (_("Save block"), get_sys_error (_("Cannot save file")));
2636 edit->force |= REDRAW_COMPLETELY;
2637 return 0;
2641 /* --------------------------------------------------------------------------------------------- */
2642 /** returns 1 on success */
2645 edit_insert_file_cmd (WEdit * edit)
2647 gchar *tmp;
2648 char *exp;
2650 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2651 exp = input_expand_dialog (_("Insert file"), _("Enter file name:"),
2652 MC_HISTORY_EDIT_INSERT_FILE, tmp);
2653 g_free (tmp);
2654 edit_push_action (edit, KEY_PRESS + edit->start_display);
2655 if (exp)
2657 if (!*exp)
2659 g_free (exp);
2660 return 0;
2662 else
2664 if (edit_insert_file (edit, exp))
2666 g_free (exp);
2667 edit->force |= REDRAW_COMPLETELY;
2668 return 1;
2670 else
2672 g_free (exp);
2673 edit_error_dialog (_("Insert file"), get_sys_error (_("Cannot insert file")));
2677 edit->force |= REDRAW_COMPLETELY;
2678 return 0;
2681 /* --------------------------------------------------------------------------------------------- */
2682 /** sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2685 edit_sort_cmd (WEdit * edit)
2687 static char *old = 0;
2688 char *exp, *tmp;
2689 long start_mark, end_mark;
2690 int e;
2692 if (eval_marks (edit, &start_mark, &end_mark))
2694 edit_error_dialog (_("Sort block"), _("You must first highlight a block of text"));
2695 return 0;
2698 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2699 edit_save_block (edit, tmp, start_mark, end_mark);
2700 g_free (tmp);
2702 exp = input_dialog (_("Run sort"),
2703 _("Enter sort options (see manpage) separated by whitespace:"),
2704 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2706 if (!exp)
2707 return 1;
2708 g_free (old);
2709 old = exp;
2710 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2711 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2712 e = system (tmp);
2713 g_free (tmp);
2714 if (e)
2716 if (e == -1 || e == 127)
2718 edit_error_dialog (_("Sort"), get_sys_error (_("Cannot execute sort command")));
2720 else
2722 char q[8];
2723 sprintf (q, "%d ", e);
2724 tmp = g_strdup_printf (_("Sort returned non-zero: %s"), q);
2725 edit_error_dialog (_("Sort"), tmp);
2726 g_free (tmp);
2728 return -1;
2731 edit->force |= REDRAW_COMPLETELY;
2733 if (edit_block_delete_cmd (edit))
2734 return 1;
2735 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2736 edit_insert_file (edit, tmp);
2737 g_free (tmp);
2738 return 0;
2741 /* --------------------------------------------------------------------------------------------- */
2743 * Ask user for a command, execute it and paste its output back to the
2744 * editor.
2748 edit_ext_cmd (WEdit * edit)
2750 char *exp, *tmp;
2751 int e;
2753 exp =
2754 input_dialog (_("Paste output of external command"),
2755 _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2757 if (!exp)
2758 return 1;
2760 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2761 e = system (tmp);
2762 g_free (tmp);
2763 g_free (exp);
2765 if (e)
2767 edit_error_dialog (_("External command"), get_sys_error (_("Cannot execute command")));
2768 return -1;
2771 edit->force |= REDRAW_COMPLETELY;
2772 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2773 edit_insert_file (edit, tmp);
2774 g_free (tmp);
2775 return 0;
2778 /* --------------------------------------------------------------------------------------------- */
2779 /** if block is 1, a block must be highlighted and the shell command
2780 processes it. If block is 0 the shell command is a straight system
2781 command, that just produces some output which is to be inserted */
2783 void
2784 edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
2786 long start_mark, end_mark;
2787 char buf[BUFSIZ];
2788 FILE *script_home = NULL;
2789 FILE *block_file = NULL;
2790 gchar *o, *h, *b, *tmp;
2791 char *quoted_name = NULL;
2793 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2794 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2795 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2797 script_home = fopen (h, "r");
2798 if (script_home == NULL)
2800 FILE *script_src = NULL;
2802 script_home = fopen (h, "w");
2803 if (script_home == NULL)
2805 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2806 edit_error_dialog ("", get_sys_error (tmp));
2807 g_free (tmp);
2808 goto edit_block_process_cmd__EXIT;
2811 script_src = fopen (o, "r");
2812 if (script_src == NULL)
2814 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2815 script_src = fopen (o, "r");
2816 if (script_src == NULL)
2818 fclose (script_home);
2819 unlink (h);
2820 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2821 edit_error_dialog ("", get_sys_error (tmp));
2822 g_free (tmp);
2823 goto edit_block_process_cmd__EXIT;
2826 while (fgets (buf, sizeof (buf), script_src))
2827 fputs (buf, script_home);
2828 fclose (script_src);
2830 if (fclose (script_home))
2832 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2833 edit_error_dialog ("", get_sys_error (tmp));
2834 g_free (tmp);
2835 goto edit_block_process_cmd__EXIT;
2837 chmod (h, 0700);
2838 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2839 edit_error_dialog ("", get_sys_error (tmp));
2840 g_free (tmp);
2843 open_error_pipe ();
2845 if (block)
2846 { /* for marked block run indent formatter */
2847 if (eval_marks (edit, &start_mark, &end_mark))
2849 edit_error_dialog (_("Process block"), _("You must first highlight a block of text"));
2850 goto edit_block_process_cmd__EXIT;
2852 edit_save_block (edit, b, start_mark, end_mark);
2853 quoted_name = name_quote (edit->filename, 0);
2855 * Run script.
2856 * Initial space is to avoid polluting bash history.
2857 * Arguments:
2858 * $1 - name of the edited file (to check its extension etc).
2859 * $2 - file containing the current block.
2860 * $3 - file where error messages should be put
2861 * (for compatibility with old scripts).
2863 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2864 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2866 else
2869 * No block selected, just execute the command for the file.
2870 * Arguments:
2871 * $1 - name of the edited file.
2873 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2874 quoted_name, (char *) NULL);
2877 if (system (tmp) == -1)
2879 edit_error_dialog (_("Process block"), _("Error calling program"));
2881 else
2884 g_free (quoted_name);
2885 close_error_pipe (D_NORMAL, NULL);
2887 edit_refresh_cmd (edit);
2888 edit->force |= REDRAW_COMPLETELY;
2890 /* insert result block */
2891 if (block && !edit_block_delete_cmd (edit))
2893 edit_insert_file (edit, b);
2894 block_file = fopen (b, "w");
2895 if (block_file != NULL)
2896 fclose (block_file);
2899 g_free (tmp);
2901 edit_block_process_cmd__EXIT:
2902 g_free (b);
2903 g_free (h);
2904 g_free (o);
2907 /* --------------------------------------------------------------------------------------------- */
2909 * prints at the cursor
2910 * @returns the number of chars printed
2914 edit_print_string (WEdit * e, const char *s)
2916 size_t i = 0;
2917 while (s[i] != '\0')
2918 edit_execute_cmd (e, CK_Insert_Char, (unsigned char) s[i++]);
2919 e->force |= REDRAW_COMPLETELY;
2920 edit_update_screen (e);
2921 return i;
2924 /* --------------------------------------------------------------------------------------------- */
2926 void
2927 edit_mail_dialog (WEdit * edit)
2929 char *tmail_to;
2930 char *tmail_subject;
2931 char *tmail_cc;
2933 static char *mail_cc_last = 0;
2934 static char *mail_subject_last = 0;
2935 static char *mail_to_last = 0;
2937 QuickWidget quick_widgets[] = {
2938 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2939 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2940 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2941 /* 3 */ QUICK_LABEL (3, 50, 7, MAIL_DLG_HEIGHT, N_("Copies to")),
2942 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2",
2943 &tmail_subject),
2944 /* 5 */ QUICK_LABEL (3, 50, 5, MAIL_DLG_HEIGHT, N_("Subject")),
2945 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2946 /* 7 */ QUICK_LABEL (3, 50, 3, MAIL_DLG_HEIGHT, N_("To")),
2947 /* 8 */ QUICK_LABEL (3, 50, 2, MAIL_DLG_HEIGHT, N_("mail -s <subject> -c <cc> <to>")),
2948 QUICK_END
2951 QuickDialog Quick_input = {
2952 50, MAIL_DLG_HEIGHT, -1, -1, N_("Mail"),
2953 "[Input Line Keys]", quick_widgets, NULL, FALSE
2956 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2957 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2958 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2960 if (quick_dialog (&Quick_input) != B_CANCEL)
2962 g_free (mail_cc_last);
2963 g_free (mail_subject_last);
2964 g_free (mail_to_last);
2965 mail_cc_last = tmail_cc;
2966 mail_subject_last = tmail_subject;
2967 mail_to_last = tmail_to;
2968 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2973 /*******************/
2974 /* Word Completion */
2975 /*******************/
2977 /* --------------------------------------------------------------------------------------------- */
2979 * Complete current word using regular expression search
2980 * backwards beginning at the current cursor position.
2983 void
2984 edit_complete_word_cmd (WEdit * edit)
2986 gsize i, max_len, word_len = 0, num_compl = 0;
2987 long word_start = 0;
2988 unsigned char *bufpos;
2989 char *match_expr;
2990 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2992 /* search start of word to be completed */
2993 if (!edit_find_word_start (edit, &word_start, &word_len))
2994 return;
2996 /* prepare match expression */
2997 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
2999 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
3000 match_expr =
3001 g_strdup_printf
3002 ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+",
3003 (int) word_len, bufpos);
3005 /* collect the possible completions */
3006 /* start search from begin to end of file */
3007 max_len =
3008 edit_collect_completions (edit, word_start, word_len, match_expr,
3009 (struct selection *) &compl, &num_compl);
3011 if (num_compl > 0)
3013 /* insert completed word if there is only one match */
3014 if (num_compl == 1)
3016 for (i = word_len; i < compl[0].len; i++)
3017 edit_insert (edit, *(compl[0].text + i));
3019 /* more than one possible completion => ask the user */
3020 else
3022 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
3023 /* !!! pressed again the selection dialog pops up, but that !!! */
3024 /* !!! seems to require a further internal state !!! */
3025 /*tty_beep (); */
3027 /* let the user select the preferred completion */
3028 editcmd_dialog_completion_show (edit, max_len, word_len,
3029 (struct selection *) &compl, num_compl);
3033 g_free (match_expr);
3034 /* release memory before return */
3035 for (i = 0; i < num_compl; i++)
3036 g_free (compl[i].text);
3039 /* --------------------------------------------------------------------------------------------- */
3041 void
3042 edit_select_codepage_cmd (WEdit * edit)
3044 #ifdef HAVE_CHARSET
3045 if (do_select_codepage ())
3046 edit_set_codeset (edit);
3048 edit->force = REDRAW_COMPLETELY;
3049 edit_refresh_cmd (edit);
3050 #else
3051 (void) edit;
3052 #endif
3055 /* --------------------------------------------------------------------------------------------- */
3057 void
3058 edit_insert_literal_cmd (WEdit * edit)
3060 int char_for_insertion = editcmd_dialog_raw_key_query (_("Insert literal"),
3061 _("Press any key:"), 0);
3062 edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
3065 /* --------------------------------------------------------------------------------------------- */
3067 void
3068 edit_execute_macro_cmd (WEdit * edit)
3070 int command =
3071 CK_Macro (editcmd_dialog_raw_key_query (_("Execute macro"), _("Press macro hotkey:"),
3072 1));
3073 if (command == CK_Macro (0))
3074 command = CK_Insert_Char;
3076 edit_execute_key_command (edit, command, -1);
3079 /* --------------------------------------------------------------------------------------------- */
3081 void
3082 edit_begin_end_macro_cmd (WEdit * edit)
3084 /* edit is a pointer to the widget */
3085 if (edit)
3087 unsigned long command = edit->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
3088 edit_execute_key_command (edit, command, -1);
3092 /* --------------------------------------------------------------------------------------------- */
3095 edit_load_forward_cmd (WEdit * edit)
3097 if (edit->modified)
3099 if (edit_query_dialog2
3100 (_("Warning"),
3101 _("Current text was modified without a file save\n"
3102 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")))
3104 edit->force |= REDRAW_COMPLETELY;
3105 return 0;
3108 if (edit_stack_iterator + 1 < MAX_HISTORY_MOVETO)
3110 if (edit_history_moveto[edit_stack_iterator + 1].line < 1)
3112 return 1;
3114 edit_stack_iterator++;
3115 if (edit_history_moveto[edit_stack_iterator].filename)
3117 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
3118 edit_history_moveto[edit_stack_iterator].line);
3119 return 0;
3121 else
3123 return 1;
3126 else
3128 return 1;
3132 /* --------------------------------------------------------------------------------------------- */
3135 edit_load_back_cmd (WEdit * edit)
3137 if (edit->modified)
3139 if (edit_query_dialog2
3140 (_("Warning"),
3141 _("Current text was modified without a file save\n"
3142 "Continue discards these changes"), _("C&ontinue"), _("&Cancel")))
3144 edit->force |= REDRAW_COMPLETELY;
3145 return 0;
3148 if (edit_stack_iterator > 0)
3150 edit_stack_iterator--;
3151 if (edit_history_moveto[edit_stack_iterator].filename)
3153 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
3154 edit_history_moveto[edit_stack_iterator].line);
3155 return 0;
3157 else
3159 return 1;
3162 else
3164 return 1;
3168 /* --------------------------------------------------------------------------------------------- */
3170 void
3171 edit_get_match_keyword_cmd (WEdit * edit)
3173 gsize word_len = 0, max_len = 0;
3174 int num_def = 0;
3175 int i;
3176 long word_start = 0;
3177 unsigned char *bufpos;
3178 char *match_expr;
3179 char *path = NULL;
3180 char *ptr = NULL;
3181 char *tagfile = NULL;
3183 etags_hash_t def_hash[MAX_DEFINITIONS];
3185 for (i = 0; i < MAX_DEFINITIONS; i++)
3187 def_hash[i].filename = NULL;
3190 /* search start of word to be completed */
3191 if (!edit_find_word_start (edit, &word_start, &word_len))
3192 return;
3194 /* prepare match expression */
3195 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE][word_start & M_EDIT_BUF_SIZE];
3196 match_expr = g_strdup_printf ("%.*s", (int) word_len, bufpos);
3198 ptr = g_get_current_dir ();
3199 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
3200 g_free (ptr);
3202 /* Recursive search file 'TAGS' in parent dirs */
3205 ptr = g_path_get_dirname (path);
3206 g_free (path);
3207 path = ptr;
3208 g_free (tagfile);
3209 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
3210 if (exist_file (tagfile))
3211 break;
3213 while (strcmp (path, G_DIR_SEPARATOR_S) != 0);
3215 if (tagfile)
3217 num_def =
3218 etags_set_definition_hash (tagfile, path, match_expr, (etags_hash_t *) & def_hash);
3219 g_free (tagfile);
3221 g_free (path);
3223 max_len = MAX_WIDTH_DEF_DIALOG;
3224 word_len = 0;
3225 if (num_def > 0)
3227 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
3228 (etags_hash_t *) & def_hash, num_def);
3230 g_free (match_expr);
3233 /* --------------------------------------------------------------------------------------------- */
3235 void
3236 edit_move_block_to_right (WEdit * edit)
3238 long start_mark, end_mark;
3239 long cur_bol, start_bol;
3241 if (eval_marks (edit, &start_mark, &end_mark))
3242 return;
3244 start_bol = edit_bol (edit, start_mark);
3245 cur_bol = edit_bol (edit, end_mark - 1);
3248 edit_cursor_move (edit, cur_bol - edit->curs1);
3249 if (option_fill_tabs_with_spaces)
3251 if (option_fake_half_tabs)
3253 insert_spaces_tab (edit, 1);
3255 else
3257 insert_spaces_tab (edit, 0);
3260 else
3262 edit_insert (edit, '\t');
3264 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
3265 if (cur_bol == 0)
3267 break;
3269 cur_bol = edit_bol (edit, cur_bol - 1);
3271 while (cur_bol >= start_bol);
3272 edit->force |= REDRAW_PAGE;
3275 /* --------------------------------------------------------------------------------------------- */
3277 void
3278 edit_move_block_to_left (WEdit * edit)
3280 long start_mark, end_mark;
3281 long cur_bol, start_bol;
3282 int i, del_tab_width;
3283 int next_char;
3285 if (eval_marks (edit, &start_mark, &end_mark))
3286 return;
3288 start_bol = edit_bol (edit, start_mark);
3289 cur_bol = edit_bol (edit, end_mark - 1);
3292 edit_cursor_move (edit, cur_bol - edit->curs1);
3293 if (option_fake_half_tabs)
3295 del_tab_width = HALF_TAB_SIZE;
3297 else
3299 del_tab_width = option_tab_spacing;
3301 next_char = edit_get_byte (edit, edit->curs1);
3302 if (next_char == '\t')
3304 edit_delete (edit, 1);
3306 else if (next_char == ' ')
3308 for (i = 1; i <= del_tab_width; i++)
3310 if (next_char == ' ')
3312 edit_delete (edit, 1);
3314 next_char = edit_get_byte (edit, edit->curs1);
3317 if (cur_bol == 0)
3319 break;
3321 cur_bol = edit_bol (edit, cur_bol - 1);
3323 while (cur_bol >= start_bol);
3324 edit->force |= REDRAW_PAGE;
3327 /* --------------------------------------------------------------------------------------------- */