Ticket #1837 (incorrect block selection)
[pantumic.git] / edit / editcmd.c
blob7bf344e5167a457efe7ce0ca543b679e71b2abfe
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 "../src/global.h"
50 #include "../src/tty/tty.h"
51 #include "../src/tty/key.h" /* XCTRL */
53 #include "../src/history.h"
54 #include "../src/widget.h" /* listbox_new() */
55 #include "../src/layout.h" /* clr_scr() */
56 #include "../src/main.h" /* mc_home source_codepage */
57 #include "../src/help.h" /* interactive_display() */
58 #include "../src/wtools.h" /* message() */
59 #include "../src/charsets.h"
60 #include "../src/selcodepage.h"
61 #include "../src/strutil.h" /* utf string functions */
62 #include "../src/mcconfig/mcconfig.h"
63 #include "../src/skin/skin.h" /* mc_skin_color_get */
65 #include "../edit/edit-impl.h"
66 #include "../edit/edit.h"
67 #include "../edit/editlock.h"
68 #include "../src/cmddef.h"
69 #include "../edit/edit-widget.h"
70 #include "../edit/editcmd_dialogs.h"
71 #include "../edit/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,
84 long finish, int *l);
86 static void
87 edit_search_cmd_search_create_bookmark(WEdit * edit)
89 int found = 0, books = 0;
90 int l = 0, l_last = -1;
91 long q = 0;
92 gsize len = 0;
94 search_create_bookmark = 0;
95 book_mark_flush (edit, -1);
97 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) {
105 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
106 books++;
108 l_last = l;
109 q = edit->search->normal_offset + 1;
112 if (found == 0) {
113 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
114 } else {
115 edit_cursor_move (edit, edit->search_start - edit->curs1);
116 edit_scroll_screen_over_cursor (edit);
120 static int
121 edit_search_cmd_callback(const void *user_data, gsize char_offset)
123 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
126 void edit_help_cmd (WEdit * edit)
128 interactive_display (NULL, "[Internal File Editor]");
129 edit->force |= REDRAW_COMPLETELY;
132 void
133 edit_refresh_cmd (WEdit * edit)
135 #ifdef HAVE_SLANG
136 int color;
138 edit_get_syntax_color (edit, -1, &color);
139 tty_touch_screen ();
140 mc_refresh ();
141 #else
142 clr_scr ();
143 repaint_screen ();
144 #endif /* !HAVE_SLANG */
145 tty_keypad (TRUE);
148 /* If 0 (quick save) then a) create/truncate <filename> file,
149 b) save to <filename>;
150 if 1 (safe save) then a) save to <tempnam>,
151 b) rename <tempnam> to <filename>;
152 if 2 (do backups) then a) save to <tempnam>,
153 b) rename <filename> to <filename.backup_ext>,
154 c) rename <tempnam> to <filename>. */
156 /* returns 0 on error, -1 on abort */
157 static int
158 edit_save_file (WEdit *edit, const char *filename)
160 char *p;
161 gchar *tmp;
162 long filelen = 0;
163 char *savename = 0;
164 gchar *real_filename;
165 int this_save_mode, fd = -1;
167 if (!filename)
168 return 0;
169 if (!*filename)
170 return 0;
172 if (*filename != PATH_SEP && edit->dir) {
173 real_filename = concat_dir_and_file (edit->dir, filename);
174 } else {
175 real_filename = g_strdup(filename);
178 this_save_mode = option_save_mode;
179 if (this_save_mode != EDIT_QUICK_SAVE) {
180 if (!vfs_file_is_local (real_filename) ||
181 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
183 * The file does not exists yet, so no safe save or
184 * backup are necessary.
186 this_save_mode = EDIT_QUICK_SAVE;
188 if (fd != -1)
189 mc_close (fd);
192 if (this_save_mode == EDIT_QUICK_SAVE &&
193 !edit->skip_detach_prompt) {
194 int rv;
195 struct stat sb;
197 rv = mc_stat (real_filename, &sb);
198 if (rv == 0 && sb.st_nlink > 1) {
199 rv = edit_query_dialog3 (_("Warning"),
200 _(" File has hard-links. Detach before saving? "),
201 _("&Yes"), _("&No"), _("&Cancel"));
202 switch (rv) {
203 case 0:
204 this_save_mode = EDIT_SAFE_SAVE;
205 /* fallthrough */
206 case 1:
207 edit->skip_detach_prompt = 1;
208 break;
209 default:
210 g_free(real_filename);
211 return -1;
215 /* Prevent overwriting changes from other editor sessions. */
216 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
218 /* The default action is "Cancel". */
219 query_set_sel(1);
221 rv = edit_query_dialog2 (
222 _("Warning"),
223 _("The file has been modified in the meantime. Save anyway?"),
224 _("&Yes"),
225 _("&Cancel"));
226 if (rv != 0){
227 g_free(real_filename);
228 return -1;
233 if (this_save_mode != EDIT_QUICK_SAVE) {
234 char *savedir, *saveprefix;
235 const char *slashpos;
236 slashpos = strrchr (real_filename, PATH_SEP);
237 if (slashpos) {
238 savedir = g_strdup (real_filename);
239 savedir[slashpos - real_filename + 1] = '\0';
240 } else
241 savedir = g_strdup (".");
242 saveprefix = concat_dir_and_file (savedir, "cooledit");
243 g_free (savedir);
244 fd = mc_mkstemps (&savename, saveprefix, NULL);
245 g_free (saveprefix);
246 if (!savename){
247 g_free(real_filename);
248 return 0;
250 /* FIXME:
251 * Close for now because mc_mkstemps use pure open system call
252 * to create temporary file and it needs to be reopened by
253 * VFS-aware mc_open().
255 close (fd);
256 } else
257 savename = g_strdup (real_filename);
259 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
260 mc_chmod (savename, edit->stat1.st_mode);
262 if ((fd =
263 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
264 edit->stat1.st_mode)) == -1)
265 goto error_save;
267 /* pipe save */
268 if ((p = edit_get_write_filter (savename, real_filename))) {
269 FILE *file;
271 mc_close (fd);
272 file = (FILE *) popen (p, "w");
274 if (file) {
275 filelen = edit_write_stream (edit, file);
276 #if 1
277 pclose (file);
278 #else
279 if (pclose (file) != 0) {
280 tmp = g_strconcat (_(" Error writing to pipe: "),
281 p, " ", (char *) NULL);
282 edit_error_dialog (_("Error"), tmp);
283 g_free(tmp);
284 g_free (p);
285 goto error_save;
287 #endif
288 } else {
289 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
290 p, " ", (char *) NULL);
292 edit_error_dialog (_("Error"),
293 get_sys_error (tmp));
294 g_free (p);
295 g_free(tmp);
296 goto error_save;
298 g_free (p);
299 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
300 long buf;
301 buf = 0;
302 filelen = edit->last_byte;
303 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
304 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
305 != EDIT_BUF_SIZE) {
306 mc_close (fd);
307 goto error_save;
309 buf++;
311 if (mc_write
312 (fd, (char *) edit->buffers1[buf],
313 edit->curs1 & M_EDIT_BUF_SIZE) !=
314 (edit->curs1 & M_EDIT_BUF_SIZE)) {
315 filelen = -1;
316 } else if (edit->curs2) {
317 edit->curs2--;
318 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
319 if (mc_write
320 (fd,
321 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
322 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
323 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
324 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
325 filelen = -1;
326 } else {
327 while (--buf >= 0) {
328 if (mc_write
329 (fd, (char *) edit->buffers2[buf],
330 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
331 filelen = -1;
332 break;
336 edit->curs2++;
338 if (mc_close (fd))
339 goto error_save;
341 /* Update the file information, especially the mtime. */
342 if (mc_stat (savename, &edit->stat1) == -1)
343 goto error_save;
344 } else { /* change line breaks */
345 FILE *file;
347 mc_close (fd);
349 file = (FILE *) fopen (savename, "w");
351 if (file) {
352 filelen = edit_write_stream (edit, file);
353 fclose (file);
354 } else {
355 char *msg;
357 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
358 edit_error_dialog (_("Error"), msg);
359 g_free (msg);
360 goto error_save;
364 if (filelen != edit->last_byte)
365 goto error_save;
367 if (this_save_mode == EDIT_DO_BACKUP) {
368 assert (option_backup_ext != NULL);
369 tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
370 if (mc_rename (real_filename, tmp) == -1){
371 g_free(tmp);
372 goto error_save;
376 if (this_save_mode != EDIT_QUICK_SAVE)
377 if (mc_rename (savename, real_filename) == -1)
378 goto error_save;
379 g_free (savename);
380 g_free(real_filename);
381 return 1;
382 error_save:
383 /* FIXME: Is this safe ?
384 * if (this_save_mode != EDIT_QUICK_SAVE)
385 * mc_unlink (savename);
387 g_free(real_filename);
388 g_free (savename);
389 return 0;
392 void
393 menu_save_mode_cmd (void)
395 /* diaog sizes */
396 const int DLG_X = 38;
397 const int DLG_Y = 13;
399 char *str_result;
401 const char *str[] =
403 N_("&Quick save"),
404 N_("&Safe save"),
405 N_("&Do backups with following extension:")
408 QuickWidget widgets[] =
410 /* 0 */
411 QUICK_BUTTON (18, DLG_X, DLG_Y - 3, DLG_Y, N_("&Cancel"), B_CANCEL, NULL),
412 /* 1 */
413 QUICK_BUTTON ( 6, DLG_X, DLG_Y - 3, DLG_Y, N_("&OK"), B_ENTER, NULL),
414 /* 2 */
415 QUICK_CHECKBOX ( 4, DLG_X, 8, DLG_Y, N_("Check &POSIX new line"), &option_check_nl_at_eof),
416 /* 3 */
417 QUICK_INPUT ( 8, DLG_X, 6, DLG_Y, option_backup_ext, 9, 0, "edit-backup-ext", &str_result),
418 /* 4 */
419 QUICK_RADIO ( 4, DLG_X, 3, DLG_Y, 3, str, &option_save_mode),
420 QUICK_END
423 QuickDialog dialog =
425 DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "),
426 "[Edit Save Mode]", widgets, FALSE
429 size_t i;
430 size_t maxlen = 0;
431 size_t w0, w1, b_len, w3;
433 assert (option_backup_ext != NULL);
435 /* OK/Cancel buttons */
436 w0 = str_term_width1 (_(widgets[0].u.button.text)) + 3;
437 w1 = str_term_width1 (_(widgets[1].u.button.text)) + 5; /* default button */
438 b_len = w0 + w1 + 3;
440 maxlen = max (b_len, (size_t) str_term_width1 (_(dialog.title)) + 2);
442 w3 = 0;
443 for (i = 0; i < 3; i++) {
444 #ifdef ENABLE_NLS
445 str[i] = _(str[i]);
446 #endif
447 w3 = max (w3, (size_t) str_term_width1 (str[i]));
450 maxlen = max (maxlen, w3 + 4);
452 dialog.xlen = min ((size_t) COLS, maxlen + 8);
454 widgets[3].u.input.len = w3;
455 widgets[1].relative_x = (dialog.xlen - b_len)/2;
456 widgets[0].relative_x = widgets[1].relative_x + w0 + 2;
458 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
459 widgets[i].x_divisions = dialog.xlen;
461 if (quick_dialog (&dialog) != B_CANCEL) {
462 g_free (option_backup_ext);
463 option_backup_ext = str_result;
467 void
468 edit_set_filename (WEdit *edit, const char *f)
470 g_free (edit->filename);
471 if (!f)
472 f = "";
473 edit->filename = g_strdup (f);
474 if (edit->dir == NULL && *f != PATH_SEP)
475 #ifdef USE_VFS
476 edit->dir = g_strdup (vfs_get_current_dir ());
477 #else
478 edit->dir = g_get_current_dir ();
479 #endif
482 static gboolean
483 edit_check_newline (WEdit *edit)
485 return !(option_check_nl_at_eof && edit->last_byte > 0
486 && edit_get_byte (edit, edit->last_byte - 1) != '\n'
487 && edit_query_dialog2 (_("Warning"),
488 _("The file you are saving is not finished with a newline"),
489 _("C&ontinue"), _("&Cancel")));
492 static char *
493 edit_get_save_file_as (WEdit *edit)
495 #define DLG_WIDTH 64
496 #define DLG_HEIGHT 14
498 static LineBreaks cur_lb = LB_ASIS;
500 char *filename = edit->filename;
502 const char *lb_names[LB_NAMES] =
504 N_("&Do not change"),
505 N_("&Unix format (LF)"),
506 N_("&Windows/DOS format (CR LF)"),
507 N_("&Macintosh format (CR)")
510 QuickWidget quick_widgets[] =
512 QUICK_BUTTON (6, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
513 QUICK_BUTTON (2, 10, DLG_HEIGHT - 3, DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
514 QUICK_RADIO (5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, LB_NAMES, lb_names, (int *) &cur_lb),
515 QUICK_LABEL (3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT, N_("Change line breaks to:")),
516 QUICK_INPUT (3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT, filename, DLG_WIDTH - 6, 0, "save-as", &filename),
517 QUICK_LABEL (2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT, N_(" Enter file name: ")),
518 QUICK_END
521 QuickDialog Quick_options =
523 DLG_WIDTH, DLG_HEIGHT, -1, -1,
524 N_(" Save As "), "[Save File As]",
525 quick_widgets, FALSE
528 if (quick_dialog (&Quick_options) != B_CANCEL) {
529 edit->lb = cur_lb;
530 return filename;
533 return NULL;
535 #undef DLG_WIDTH
536 #undef DLG_HEIGHT
539 /* Here we want to warn the users of overwriting an existing file,
540 but only if they have made a change to the filename */
541 /* returns 1 on success */
543 edit_save_as_cmd (WEdit *edit)
545 /* This heads the 'Save As' dialog box */
546 char *exp;
547 int save_lock = 0;
548 int different_filename = 0;
550 if (!edit_check_newline (edit))
551 return 0;
553 exp = edit_get_save_file_as (edit);
554 edit_push_action (edit, KEY_PRESS + edit->start_display);
556 if (exp) {
557 if (!*exp) {
558 g_free (exp);
559 edit->force |= REDRAW_COMPLETELY;
560 return 0;
561 } else {
562 int rv;
563 if (strcmp (edit->filename, exp)) {
564 int file;
565 different_filename = 1;
566 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
567 /* the file exists */
568 mc_close (file);
569 /* Overwrite the current file or cancel the operation */
570 if (edit_query_dialog2
571 (_("Warning"),
572 _(" A file already exists with this name. "),
573 _("&Overwrite"), _("&Cancel"))) {
574 edit->force |= REDRAW_COMPLETELY;
575 g_free (exp);
576 return 0;
578 } else {
579 edit->stat1.st_mode |= S_IWUSR;
581 save_lock = edit_lock_file (exp);
582 } else {
583 /* filenames equal, check if already locked */
584 if (!edit->locked && !edit->delete_file)
585 save_lock = edit_lock_file (exp);
588 if (different_filename)
591 * Allow user to write into saved (under another name) file
592 * even if original file had r/o user permissions.
594 edit->stat1.st_mode |= S_IWRITE;
597 rv = edit_save_file (edit, exp);
598 switch (rv) {
599 case 1:
600 /* Succesful, so unlock both files */
601 if (different_filename) {
602 if (save_lock)
603 edit_unlock_file (exp);
604 if (edit->locked)
605 edit->locked = edit_unlock_file (edit->filename);
606 } else {
607 if (edit->locked || save_lock)
608 edit->locked = edit_unlock_file (edit->filename);
611 edit_set_filename (edit, exp);
612 if (edit->lb != LB_ASIS)
613 edit_reload(edit, exp);
614 g_free (exp);
615 edit->modified = 0;
616 edit->delete_file = 0;
617 if (different_filename)
618 edit_load_syntax (edit, NULL, option_syntax_type);
619 edit->force |= REDRAW_COMPLETELY;
620 return 1;
621 default:
622 edit_error_dialog (_(" Save As "),
623 get_sys_error (_
624 (" Cannot save file. ")));
625 /* fallthrough */
626 case -1:
627 /* Failed, so maintain modify (not save) lock */
628 if (save_lock)
629 edit_unlock_file (exp);
630 g_free (exp);
631 edit->force |= REDRAW_COMPLETELY;
632 return 0;
636 edit->force |= REDRAW_COMPLETELY;
637 return 0;
640 /* {{{ Macro stuff starts here */
642 /* creates a macro file if it doesn't exist */
643 static FILE *edit_open_macro_file (const char *r)
645 gchar *filename;
646 FILE *fd;
647 int file;
648 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
649 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
650 g_free(filename);
651 return 0;
653 close (file);
654 fd = fopen (filename, r);
655 g_free(filename);
656 return fd;
659 #define MAX_MACROS 1024
660 static int saved_macro[MAX_MACROS + 1];
661 static int saved_macros_loaded = 0;
664 This is just to stop the macro file be loaded over and over for keys
665 that aren't defined to anything. On slow systems this could be annoying.
667 static int
668 macro_exists (int k)
670 int i;
671 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
672 if (saved_macro[i] == k)
673 return i;
674 return -1;
677 /* returns 1 on error */
678 static int
679 edit_delete_macro (WEdit * edit, int k)
681 gchar *tmp, *tmp2;
682 struct macro macro[MAX_MACRO_LENGTH];
683 FILE *f, *g;
684 int s, i, n, j = 0;
686 (void) edit;
688 if (saved_macros_loaded)
689 if ((j = macro_exists (k)) < 0)
690 return 0;
691 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
692 g = fopen (tmp , "w");
693 g_free(tmp);
694 if (!g) {
695 edit_error_dialog (_(" Delete macro "),
696 get_sys_error (_(" Cannot open temp file ")));
697 return 1;
699 f = edit_open_macro_file ("r");
700 if (!f) {
701 edit_error_dialog (_(" Delete macro "),
702 get_sys_error (_(" Cannot open macro file ")));
703 fclose (g);
704 return 1;
706 for (;;) {
707 n = fscanf (f, ("key '%d 0': "), &s);
708 if (!n || n == EOF)
709 break;
710 n = 0;
711 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
712 n++;
713 fscanf (f, ";\n");
714 if (s != k) {
715 fprintf (g, ("key '%d 0': "), s);
716 for (i = 0; i < n; i++)
717 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
718 fprintf (g, ";\n");
721 fclose (f);
722 fclose (g);
723 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
724 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
725 if (rename ( tmp, tmp2) == -1) {
726 edit_error_dialog (_(" Delete macro "),
727 get_sys_error (_(" Cannot overwrite macro file ")));
728 g_free(tmp);
729 g_free(tmp2);
730 return 1;
732 g_free(tmp);
733 g_free(tmp2);
735 if (saved_macros_loaded)
736 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
737 return 0;
740 /* returns 0 on error */
741 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
743 FILE *f;
744 int s, i;
746 edit_push_action (edit, KEY_PRESS + edit->start_display);
747 s = editcmd_dialog_raw_key_query (_(" Save macro "),
748 _(" Press the macro's new hotkey: "), 1);
749 edit->force |= REDRAW_COMPLETELY;
750 if (s) {
751 if (edit_delete_macro (edit, s))
752 return 0;
753 f = edit_open_macro_file ("a+");
754 if (f) {
755 fprintf (f, ("key '%d 0': "), s);
756 for (i = 0; i < n; i++)
757 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
758 fprintf (f, ";\n");
759 fclose (f);
760 if (saved_macros_loaded) {
761 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
762 saved_macro[i] = s;
764 return 1;
765 } else
766 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
768 return 0;
771 void edit_delete_macro_cmd (WEdit * edit)
773 int command;
775 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
776 _ (" Press macro hotkey: "), 1);
778 if (!command)
779 return;
781 edit_delete_macro (edit, command);
784 /* return 0 on error */
785 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
787 FILE *f;
788 int s, i = 0, found = 0;
790 (void) edit;
792 if (saved_macros_loaded)
793 if (macro_exists (k) < 0)
794 return 0;
796 if ((f = edit_open_macro_file ("r"))) {
797 struct macro dummy;
798 do {
799 int u;
800 u = fscanf (f, ("key '%d 0': "), &s);
801 if (!u || u == EOF)
802 break;
803 if (!saved_macros_loaded)
804 saved_macro[i++] = s;
805 if (!found) {
806 *n = 0;
807 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
808 (*n)++;
809 } else {
810 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
812 fscanf (f, ";\n");
813 if (s == k)
814 found = 1;
815 } while (!found || !saved_macros_loaded);
816 if (!saved_macros_loaded) {
817 saved_macro[i] = 0;
818 saved_macros_loaded = 1;
820 fclose (f);
821 return found;
822 } else
823 edit_error_dialog (_(" Load macro "),
824 get_sys_error (_(" Cannot open macro file ")));
825 return 0;
828 /* }}} Macro stuff starts here */
830 /* returns 1 on success */
831 int edit_save_confirm_cmd (WEdit * edit)
833 gchar *f = NULL;
835 if (!edit_check_newline (edit))
836 return 0;
838 if (edit_confirm_save) {
839 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
840 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
841 g_free(f);
842 return 0;
844 g_free(f);
846 return edit_save_cmd (edit);
850 /* returns 1 on success */
851 static int
852 edit_save_cmd (WEdit *edit)
854 int res, save_lock = 0;
856 if (!edit->locked && !edit->delete_file)
857 save_lock = edit_lock_file (edit->filename);
858 res = edit_save_file (edit, edit->filename);
860 /* Maintain modify (not save) lock on failure */
861 if ((res > 0 && edit->locked) || save_lock)
862 edit->locked = edit_unlock_file (edit->filename);
864 /* On failure try 'save as', it does locking on its own */
865 if (!res)
866 return edit_save_as_cmd (edit);
867 edit->force |= REDRAW_COMPLETELY;
868 if (res > 0) {
869 edit->delete_file = 0;
870 edit->modified = 0;
873 return 1;
877 /* returns 1 on success */
878 int edit_new_cmd (WEdit * edit)
880 if (edit->modified) {
881 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
882 edit->force |= REDRAW_COMPLETELY;
883 return 0;
886 edit->force |= REDRAW_COMPLETELY;
888 return edit_renew (edit); /* if this gives an error, something has really screwed up */
891 /* returns 1 on error */
892 static int
893 edit_load_file_from_filename (WEdit * edit, char *exp)
895 int prev_locked = edit->locked;
896 char *prev_filename = g_strdup (edit->filename);
898 if (!edit_reload (edit, exp)) {
899 g_free (prev_filename);
900 return 1;
903 if (prev_locked)
904 edit_unlock_file (prev_filename);
905 g_free (prev_filename);
906 return 0;
909 static void
910 edit_load_syntax_file (WEdit * edit)
912 char *extdir;
913 int dir = 0;
915 if (geteuid () == 0) {
916 dir = query_dialog (_("Syntax file edit"),
917 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
918 _("&User"), _("&System Wide"));
921 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
922 if (!exist_file(extdir)) {
923 g_free (extdir);
924 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
927 if (dir == 0) {
928 char *buffer;
930 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
931 check_for_default (extdir, buffer);
932 edit_load_file_from_filename (edit, buffer);
933 g_free (buffer);
934 } else if (dir == 1)
935 edit_load_file_from_filename (edit, extdir);
937 g_free (extdir);
940 static void
941 edit_load_menu_file (WEdit * edit)
943 char *buffer;
944 char *menufile;
945 int dir = 0;
947 dir = query_dialog (
948 _(" Menu edit "),
949 _(" Which menu file do you want to edit? "), D_NORMAL,
950 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
953 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
955 if (!exist_file (menufile)) {
956 g_free (menufile);
957 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
960 switch (dir) {
961 case 0:
962 buffer = g_strdup (EDIT_LOCAL_MENU);
963 check_for_default (menufile, buffer);
964 chmod (buffer, 0600);
965 break;
967 case 1:
968 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
969 check_for_default (menufile, buffer);
970 break;
972 case 2:
973 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
974 if (!exist_file (buffer)) {
975 g_free (buffer);
976 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
978 break;
980 default:
981 g_free (menufile);
982 return;
985 edit_load_file_from_filename (edit, buffer);
987 g_free (buffer);
988 g_free (menufile);
992 edit_load_cmd (WEdit *edit, edit_current_file_t what)
994 char *exp;
996 if (edit->modified
997 && (edit_query_dialog2
998 (_("Warning"),
999 _(" Current text was modified without a file save. \n"
1000 " Continue discards these changes. "),
1001 _("C&ontinue"), _("&Cancel")) == 1)) {
1002 edit->force |= REDRAW_COMPLETELY;
1003 return 0;
1006 switch (what) {
1007 case EDIT_FILE_COMMON:
1008 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
1009 MC_HISTORY_EDIT_LOAD, edit->filename);
1011 if (exp) {
1012 if (*exp)
1013 edit_load_file_from_filename (edit, exp);
1014 g_free (exp);
1016 break;
1018 case EDIT_FILE_SYNTAX:
1019 edit_load_syntax_file (edit);
1020 break;
1022 case EDIT_FILE_MENU:
1023 edit_load_menu_file (edit);
1024 break;
1026 default:
1027 break;
1030 edit->force |= REDRAW_COMPLETELY;
1031 return 0;
1035 if mark2 is -1 then marking is from mark1 to the cursor.
1036 Otherwise its between the markers. This handles this.
1037 Returns 1 if no text is marked.
1039 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1041 if (edit->mark1 != edit->mark2) {
1042 if (edit->mark2 >= 0) {
1043 *start_mark = min (edit->mark1, edit->mark2);
1044 *end_mark = max (edit->mark1, edit->mark2);
1045 } else {
1046 int diff;
1047 *start_mark = min (edit->mark1, edit->curs1);
1048 *end_mark = max (edit->mark1, edit->curs1);
1049 if (column_highlighting) {
1050 diff = (*start_mark - edit_bol (edit, *start_mark)) -
1051 (*end_mark - edit_bol (edit, *end_mark));
1052 if (diff > 0) {
1053 *start_mark -= diff;
1054 *end_mark += diff;
1057 edit->column2 = edit->curs_col + edit->over_col;
1059 return 0;
1060 } else {
1061 *start_mark = *end_mark = 0;
1062 edit->column2 = edit->column1 = 0;
1063 return 1;
1067 #define space_width 1
1069 void
1070 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1072 long cursor;
1073 int i, col;
1074 cursor = edit->curs1;
1075 col = edit_get_col (edit);
1076 for (i = 0; i < size; i++) {
1077 if (data[i] == '\n') { /* fill in and move to next line */
1078 int l;
1079 long p;
1080 if (edit_get_byte (edit, edit->curs1) != '\n') {
1081 l = width - (edit_get_col (edit) - col);
1082 while (l > 0) {
1083 edit_insert (edit, ' ');
1084 l -= space_width;
1087 for (p = edit->curs1;; p++) {
1088 if (p == edit->last_byte) {
1089 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1090 edit_insert_ahead (edit, '\n');
1091 p++;
1092 break;
1094 if (edit_get_byte (edit, p) == '\n') {
1095 p++;
1096 break;
1099 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1100 l = col - edit_get_col (edit);
1101 while (l >= space_width) {
1102 edit_insert (edit, ' ');
1103 l -= space_width;
1105 continue;
1107 edit_insert (edit, data[i]);
1109 edit_cursor_move (edit, cursor - edit->curs1);
1112 #define TEMP_BUF_LEN 1024
1115 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1117 long cursor;
1118 int i, col;
1119 int blocklen = -1, width;
1120 unsigned char *data;
1121 cursor = edit->curs1;
1122 col = edit_get_col (edit);
1123 data = g_malloc (TEMP_BUF_LEN);
1124 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1125 for (width = 0; width < blocklen; width++) {
1126 if (data[width] == '\n')
1127 break;
1129 for (i = 0; i < blocklen; i++) {
1130 if (data[i] == '\n') { /* fill in and move to next line */
1131 int l;
1132 long p;
1133 if (edit_get_byte (edit, edit->curs1) != '\n') {
1134 l = width - (edit_get_col (edit) - col);
1135 while (l > 0) {
1136 edit_insert (edit, ' ');
1137 l -= space_width;
1140 for (p = edit->curs1;; p++) {
1141 if (p == edit->last_byte) {
1142 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1143 edit_insert_ahead (edit, '\n');
1144 p++;
1145 break;
1147 if (edit_get_byte (edit, p) == '\n') {
1148 p++;
1149 break;
1152 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1153 l = col - edit_get_col (edit);
1154 while (l >= space_width) {
1155 edit_insert (edit, ' ');
1156 l -= space_width;
1158 continue;
1160 edit_insert (edit, data[i]);
1163 edit_cursor_move (edit, cursor - edit->curs1);
1164 g_free(data);
1165 edit->force |= REDRAW_PAGE;
1166 return blocklen;
1169 void
1170 edit_block_copy_cmd (WEdit *edit)
1172 long start_mark, end_mark, current = edit->curs1;
1173 int size;
1174 unsigned char *copy_buf;
1176 edit_update_curs_col (edit);
1177 if (eval_marks (edit, &start_mark, &end_mark))
1178 return;
1180 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1182 /* all that gets pushed are deletes hence little space is used on the stack */
1184 edit_push_markers (edit);
1186 if (column_highlighting) {
1187 edit_insert_column_of_text (edit, copy_buf, size,
1188 abs (edit->column2 - edit->column1));
1189 } else {
1190 while (size--)
1191 edit_insert_ahead (edit, copy_buf[size]);
1194 g_free (copy_buf);
1195 edit_scroll_screen_over_cursor (edit);
1197 if (column_highlighting) {
1198 edit_set_markers (edit, 0, 0, 0, 0);
1199 edit_push_action (edit, COLUMN_ON);
1200 column_highlighting = 0;
1201 } else if (start_mark < current && end_mark > current)
1202 edit_set_markers (edit, start_mark,
1203 end_mark + end_mark - start_mark, 0, 0);
1205 edit->force |= REDRAW_PAGE;
1209 void
1210 edit_block_move_cmd (WEdit *edit)
1212 long count;
1213 long current;
1214 unsigned char *copy_buf;
1215 long start_mark, end_mark;
1216 int deleted = 0;
1217 int x = 0;
1219 if (eval_marks (edit, &start_mark, &end_mark))
1220 return;
1221 if (column_highlighting) {
1222 edit_update_curs_col (edit);
1223 x = edit->curs_col;
1224 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1225 if ((x > edit->column1 && x < edit->column2)
1226 || (x > edit->column2 && x < edit->column1))
1227 return;
1228 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1229 return;
1231 if ((end_mark - start_mark) > option_max_undo / 2)
1232 if (edit_query_dialog2
1233 (_("Warning"),
1235 (" Block is large, you may not be able to undo this action. "),
1236 _("C&ontinue"), _("&Cancel")))
1237 return;
1239 edit_push_markers (edit);
1240 current = edit->curs1;
1241 if (column_highlighting) {
1242 int size, c1, c2, line;
1243 line = edit->curs_line;
1244 if (edit->mark2 < 0)
1245 edit_mark_cmd (edit, 0);
1246 c1 = min (edit->column1, edit->column2);
1247 c2 = max (edit->column1, edit->column2);
1248 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1249 if (x < c2) {
1250 edit_block_delete_cmd (edit);
1251 deleted = 1;
1253 edit_move_to_line (edit, line);
1254 edit_cursor_move (edit,
1255 edit_move_forward3 (edit,
1256 edit_bol (edit, edit->curs1),
1257 x, 0) - edit->curs1);
1258 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1259 if (!deleted) {
1260 line = edit->curs_line;
1261 edit_update_curs_col (edit);
1262 x = edit->curs_col;
1263 edit_block_delete_cmd (edit);
1264 edit_move_to_line (edit, line);
1265 edit_cursor_move (edit,
1266 edit_move_forward3 (edit,
1267 edit_bol (edit,
1268 edit->curs1),
1269 x, 0) - edit->curs1);
1271 edit_set_markers (edit, 0, 0, 0, 0);
1272 edit_push_action (edit, COLUMN_ON);
1273 column_highlighting = 0;
1274 } else {
1275 copy_buf = g_malloc (end_mark - start_mark);
1276 edit_cursor_move (edit, start_mark - edit->curs1);
1277 edit_scroll_screen_over_cursor (edit);
1278 count = start_mark;
1279 while (count < end_mark) {
1280 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1281 count++;
1283 edit_scroll_screen_over_cursor (edit);
1284 edit_cursor_move (edit,
1285 current - edit->curs1 -
1286 (((current - edit->curs1) >
1287 0) ? end_mark - start_mark : 0));
1288 edit_scroll_screen_over_cursor (edit);
1289 while (count-- > start_mark)
1290 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1291 edit_set_markers (edit, edit->curs1,
1292 edit->curs1 + end_mark - start_mark, 0, 0);
1294 edit_scroll_screen_over_cursor (edit);
1295 g_free (copy_buf);
1296 edit->force |= REDRAW_PAGE;
1299 static void
1300 edit_delete_column_of_text (WEdit * edit)
1302 long p, q, r, m1, m2;
1303 int b, c, d;
1304 int n;
1306 eval_marks (edit, &m1, &m2);
1307 n = edit_move_forward (edit, m1, 0, m2) + 1;
1308 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1309 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1311 b = max(min (c, d), min (edit->column1, edit->column2));
1312 c = max (c, d + edit->over_col);
1314 while (n--) {
1315 r = edit_bol (edit, edit->curs1);
1316 p = edit_move_forward3 (edit, r, b, 0);
1317 q = edit_move_forward3 (edit, r, c, 0);
1318 if (p < m1)
1319 p = m1;
1320 if (q > m2)
1321 q = m2;
1322 edit_cursor_move (edit, p - edit->curs1);
1323 while (q > p) { /* delete line between margins */
1324 if (edit_get_byte (edit, edit->curs1) != '\n')
1325 edit_delete (edit, 1);
1326 q--;
1328 if (n) /* move to next line except on the last delete */
1329 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1333 /* if success return 0 */
1334 static int
1335 edit_block_delete (WEdit *edit)
1337 long count;
1338 long start_mark, end_mark;
1339 if (eval_marks (edit, &start_mark, &end_mark))
1340 return 0;
1341 if (column_highlighting && edit->mark2 < 0)
1342 edit_mark_cmd (edit, 0);
1343 if ((end_mark - start_mark) > option_max_undo / 2) {
1344 /* Warning message with a query to continue or cancel the operation */
1345 if (edit_query_dialog2
1346 (_("Warning"),
1348 (" Block is large, you may not be able to undo this action. "),
1349 _("C&ontinue"), _("&Cancel"))) {
1350 return 1;
1353 edit_push_markers (edit);
1354 edit_cursor_move (edit, start_mark - edit->curs1);
1355 edit_scroll_screen_over_cursor (edit);
1356 count = start_mark;
1357 if (start_mark < end_mark) {
1358 if (column_highlighting) {
1359 if (edit->mark2 < 0)
1360 edit_mark_cmd (edit, 0);
1361 edit_delete_column_of_text (edit);
1362 } else {
1363 while (count < end_mark) {
1364 edit_delete (edit, 1);
1365 count++;
1369 edit_set_markers (edit, 0, 0, 0, 0);
1370 edit->force |= REDRAW_PAGE;
1371 return 0;
1374 /* returns 1 if canceelled by user */
1375 int edit_block_delete_cmd (WEdit * edit)
1377 long start_mark, end_mark;
1378 if (eval_marks (edit, &start_mark, &end_mark)) {
1379 edit_delete_line (edit);
1380 return 0;
1382 return edit_block_delete (edit);
1385 #define INPUT_INDEX 9
1387 static gboolean
1388 editcmd_find (WEdit *edit, gsize *len)
1390 off_t search_start = edit->search_start;
1391 off_t search_end;
1392 long start_mark = 0;
1393 long end_mark = edit->last_byte;
1394 int mark_res = 0;
1396 if (edit->only_in_selection) {
1397 mark_res = eval_marks(edit, &start_mark, &end_mark);
1398 if (mark_res != 0) {
1399 edit->search->error = MC_SEARCH_E_NOTFOUND;
1400 edit->search->error_str = g_strdup(_(" Search string not found "));
1401 return FALSE;
1403 if (edit->replace_backwards) {
1404 if (search_start > end_mark || search_start <= start_mark) {
1405 search_start = end_mark;
1407 } else {
1408 if (search_start < start_mark || search_start >= end_mark) {
1409 search_start = start_mark;
1412 } else {
1413 if (edit->replace_backwards)
1414 end_mark = max(1, edit->curs1) - 1;
1416 if (edit->replace_backwards) {
1417 search_end = end_mark;
1418 while ((int) search_start >= start_mark) {
1419 if (search_end > search_start + edit->search->original_len
1420 && mc_search_is_fixed_search_str(edit->search)) {
1421 search_end = search_start + edit->search->original_len;
1423 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1424 && edit->search->normal_offset == search_start ) {
1425 return TRUE;
1427 search_start--;
1429 edit->search->error_str = g_strdup(_(" Search string not found "));
1430 } else {
1431 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1433 return FALSE;
1437 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1438 (and the above) routines to work properly - paul */
1440 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1442 static char *
1443 edit_replace_cmd__conv_to_display(char *str)
1445 #ifdef HAVE_CHARSET
1446 GString *tmp;
1447 tmp = str_convert_to_display (str);
1449 if (tmp && tmp->len){
1450 g_free(str);
1451 str = tmp->str;
1453 g_string_free (tmp, FALSE);
1454 return str;
1455 #else
1456 return g_strdup(str);
1457 #endif
1460 static char *
1461 edit_replace_cmd__conv_to_input(char *str)
1463 #ifdef HAVE_CHARSET
1464 GString *tmp;
1465 tmp = str_convert_to_input (str);
1467 if (tmp && tmp->len){
1468 g_free(str);
1469 str = tmp->str;
1471 g_string_free (tmp, FALSE);
1472 return str;
1473 #else
1474 return g_strdup(str);
1475 #endif
1477 /* call with edit = 0 before shutdown to close memory leaks */
1478 void
1479 edit_replace_cmd (WEdit *edit, int again)
1481 /* 1 = search string, 2 = replace with */
1482 static char *saved1 = NULL; /* saved default[123] */
1483 static char *saved2 = NULL;
1484 char *input1 = NULL; /* user input from the dialog */
1485 char *input2 = NULL;
1486 int replace_yes;
1487 long times_replaced = 0, last_search;
1488 gboolean once_found = FALSE;
1490 if (!edit) {
1491 g_free (saved1), saved1 = NULL;
1492 g_free (saved2), saved2 = NULL;
1493 return;
1496 last_search = edit->last_byte;
1498 edit->force |= REDRAW_COMPLETELY;
1500 if (again && !saved1 && !saved2)
1501 again = 0;
1503 if (again) {
1504 input1 = g_strdup (saved1 ? saved1 : "");
1505 input2 = g_strdup (saved2 ? saved2 : "");
1506 } else {
1507 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1508 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1510 edit_push_action (edit, KEY_PRESS + edit->start_display);
1512 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1514 g_free (disp1);
1515 g_free (disp2);
1517 if (input1 == NULL || *input1 == '\0') {
1518 edit->force = REDRAW_COMPLETELY;
1519 goto cleanup;
1522 input1 = edit_replace_cmd__conv_to_input(input1);
1523 input2 = edit_replace_cmd__conv_to_input(input2);
1525 g_free (saved1), saved1 = g_strdup (input1);
1526 g_free (saved2), saved2 = g_strdup (input2);
1528 if (edit->search) {
1529 mc_search_free(edit->search);
1530 edit->search = NULL;
1534 if (!edit->search) {
1535 edit->search = mc_search_new(input1, -1);
1536 if (edit->search == NULL) {
1537 edit->search_start = edit->curs1;
1538 return;
1540 edit->search->search_type = edit->search_type;
1541 edit->search->is_all_charsets = edit->all_codepages;
1542 edit->search->is_case_sentitive = edit->replace_case;
1543 edit->search->whole_words = edit->whole_words;
1544 edit->search->search_fn = edit_search_cmd_callback;
1547 if (edit->found_len && edit->search_start == edit->found_start + 1
1548 && edit->replace_backwards)
1549 edit->search_start--;
1551 if (edit->found_len && edit->search_start == edit->found_start - 1
1552 && !edit->replace_backwards)
1553 edit->search_start++;
1555 do {
1556 gsize len = 0;
1557 long new_start;
1559 if (! editcmd_find(edit, &len)) {
1560 if (!(edit->search->error == MC_SEARCH_E_OK ||
1561 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1562 edit_error_dialog (_ ("Search"), edit->search->error_str);
1564 break;
1566 once_found = TRUE;
1567 new_start = edit->search->normal_offset;
1569 edit->search_start = new_start = edit->search->normal_offset;
1570 /*returns negative on not found or error in pattern */
1572 if (edit->search_start >= 0) {
1573 guint i;
1575 edit->found_start = edit->search_start;
1576 i = edit->found_len = len;
1578 edit_cursor_move (edit, edit->search_start - edit->curs1);
1579 edit_scroll_screen_over_cursor (edit);
1581 replace_yes = 1;
1583 if (edit->replace_mode == 0) {
1584 int l;
1585 l = edit->curs_row - edit->num_widget_lines / 3;
1586 if (l > 0)
1587 edit_scroll_downward (edit, l);
1588 if (l < 0)
1589 edit_scroll_upward (edit, -l);
1591 edit_scroll_screen_over_cursor (edit);
1592 edit->force |= REDRAW_PAGE;
1593 edit_render_keypress (edit);
1595 /*so that undo stops at each query */
1596 edit_push_key_press (edit);
1597 /* and prompt 2/3 down */
1598 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1599 case B_ENTER:
1600 replace_yes = 1;
1601 break;
1602 case B_SKIP_REPLACE:
1603 replace_yes = 0;
1604 break;
1605 case B_REPLACE_ALL:
1606 edit->replace_mode=1;
1607 break;
1608 case B_CANCEL:
1609 replace_yes = 0;
1610 edit->replace_mode = -1;
1611 break;
1614 if (replace_yes) { /* delete then insert new */
1615 GString *repl_str, *tmp_str;
1616 tmp_str = g_string_new(input2);
1618 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1619 g_string_free(tmp_str, TRUE);
1620 if (edit->search->error != MC_SEARCH_E_OK)
1622 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1623 break;
1626 while (i--)
1627 edit_delete (edit, 1);
1629 while (++i < repl_str->len)
1630 edit_insert (edit, repl_str->str[i]);
1632 g_string_free(repl_str, TRUE);
1633 edit->found_len = i;
1635 /* so that we don't find the same string again */
1636 if (edit->replace_backwards) {
1637 last_search = edit->search_start;
1638 edit->search_start--;
1639 } else {
1640 edit->search_start += i;
1641 last_search = edit->last_byte;
1643 edit_scroll_screen_over_cursor (edit);
1644 } else {
1645 const char *msg = _(" Replace ");
1646 /* try and find from right here for next search */
1647 edit->search_start = edit->curs1;
1648 edit_update_curs_col (edit);
1650 edit->force |= REDRAW_PAGE;
1651 edit_render_keypress (edit);
1652 if (times_replaced) {
1653 message (D_NORMAL, msg, _(" %ld replacements made. "),
1654 times_replaced);
1655 } else
1656 query_dialog (msg, _(" Search string not found "),
1657 D_NORMAL, 1, _("&OK"));
1658 edit->replace_mode = -1;
1660 } while (edit->replace_mode >= 0);
1662 edit->force = REDRAW_COMPLETELY;
1663 edit_scroll_screen_over_cursor (edit);
1664 cleanup:
1665 g_free (input1);
1666 g_free (input2);
1670 void edit_search_cmd (WEdit * edit, int again)
1672 char *search_string = NULL, *search_string_dup = NULL;
1674 gsize len = 0;
1676 if (!edit)
1677 return;
1679 if (edit->search != NULL) {
1680 search_string = g_strndup(edit->search->original, edit->search->original_len);
1681 search_string_dup = search_string;
1682 } else {
1683 GList *history;
1684 history = history_get (MC_HISTORY_SHARED_SEARCH);
1685 if (history != NULL && history->data != NULL) {
1686 search_string_dup = search_string = (char *) g_strdup(history->data);
1687 history = g_list_first (history);
1688 g_list_foreach (history, (GFunc) g_free, NULL);
1689 g_list_free (history);
1691 edit->search_start = edit->curs1;
1694 if (!again) {
1695 #ifdef HAVE_CHARSET
1696 GString *tmp;
1697 if (search_string && *search_string) {
1698 tmp = str_convert_to_display (search_string);
1700 g_free(search_string_dup);
1701 search_string_dup = NULL;
1703 if (tmp && tmp->len)
1704 search_string = search_string_dup = tmp->str;
1705 g_string_free (tmp, FALSE);
1707 #endif /* HAVE_CHARSET */
1708 editcmd_dialog_search_show (edit, &search_string);
1709 #ifdef HAVE_CHARSET
1710 if (search_string && *search_string) {
1711 tmp = str_convert_to_input (search_string);
1712 if (tmp && tmp->len)
1713 search_string = tmp->str;
1715 g_string_free (tmp, FALSE);
1717 if (search_string_dup)
1718 g_free(search_string_dup);
1720 #endif /* HAVE_CHARSET */
1722 edit_push_action (edit, KEY_PRESS + edit->start_display);
1724 if (!search_string) {
1725 edit->force |= REDRAW_COMPLETELY;
1726 edit_scroll_screen_over_cursor (edit);
1727 return;
1730 if (edit->search) {
1731 mc_search_free(edit->search);
1732 edit->search = NULL;
1736 if (!edit->search) {
1737 edit->search = mc_search_new(search_string, -1);
1738 if (edit->search == NULL) {
1739 edit->search_start = edit->curs1;
1740 return;
1742 edit->search->search_type = edit->search_type;
1743 edit->search->is_all_charsets = edit->all_codepages;
1744 edit->search->is_case_sentitive = edit->replace_case;
1745 edit->search->whole_words = edit->whole_words;
1746 edit->search->search_fn = edit_search_cmd_callback;
1749 if (search_create_bookmark) {
1750 edit_search_cmd_search_create_bookmark(edit);
1751 } else {
1752 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1753 edit->search_start--;
1755 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1756 edit->search_start++;
1759 if (editcmd_find(edit, &len)) {
1760 edit->found_start = edit->search_start = edit->search->normal_offset;
1761 edit->found_len = len;
1762 edit->over_col = 0;
1763 edit_cursor_move (edit, edit->search_start - edit->curs1);
1764 edit_scroll_screen_over_cursor (edit);
1765 if (edit->replace_backwards)
1766 edit->search_start--;
1767 else
1768 edit->search_start++;
1769 } else {
1770 edit->search_start = edit->curs1;
1771 if (edit->search->error_str)
1772 edit_error_dialog (_ ("Search"), edit->search->error_str);
1776 edit->force |= REDRAW_COMPLETELY;
1777 edit_scroll_screen_over_cursor (edit);
1782 * Check if it's OK to close the editor. If there are unsaved changes,
1783 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1786 edit_ok_to_exit (WEdit *edit)
1788 if (!edit->modified)
1789 return 1;
1791 if (!edit_check_newline (edit))
1792 return 0;
1794 switch (edit_query_dialog3
1795 (_("Quit"), _(" File was modified, Save with exit? "),
1796 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1797 case 1:
1798 edit_push_markers (edit);
1799 edit_set_markers (edit, 0, 0, 0, 0);
1800 if (!edit_save_cmd (edit))
1801 return 0;
1802 break;
1803 case 2:
1804 break;
1805 case 0:
1806 case -1:
1807 return 0;
1810 return 1;
1813 /* Return a null terminated length of text. Result must be g_free'd */
1814 static unsigned char *
1815 edit_get_block (WEdit *edit, long start, long finish, int *l)
1817 unsigned char *s, *r;
1818 r = s = g_malloc (finish - start + 1);
1819 if (column_highlighting) {
1820 *l = 0;
1821 /* copy from buffer, excluding chars that are out of the column 'margins' */
1822 while (start < finish) {
1823 int c, x;
1824 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1825 start);
1826 c = edit_get_byte (edit, start);
1827 if ((x >= edit->column1 && x < edit->column2)
1828 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1829 *s++ = c;
1830 (*l)++;
1832 start++;
1834 } else {
1835 *l = finish - start;
1836 while (start < finish)
1837 *s++ = edit_get_byte (edit, start++);
1839 *s = 0;
1840 return r;
1843 /* save block, returns 1 on success */
1845 edit_save_block (WEdit * edit, const char *filename, long start,
1846 long finish)
1848 int len, file;
1850 if ((file =
1851 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1852 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1853 return 0;
1855 if (column_highlighting) {
1856 int r;
1857 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1858 if (r > 0) {
1859 unsigned char *block, *p;
1860 p = block = edit_get_block (edit, start, finish, &len);
1861 while (len) {
1862 r = mc_write (file, p, len);
1863 if (r < 0)
1864 break;
1865 p += r;
1866 len -= r;
1868 g_free (block);
1870 } else {
1871 unsigned char *buf;
1872 int i = start, end;
1873 len = finish - start;
1874 buf = g_malloc (TEMP_BUF_LEN);
1875 while (start != finish) {
1876 end = min (finish, start + TEMP_BUF_LEN);
1877 for (; i < end; i++)
1878 buf[i - start] = edit_get_byte (edit, i);
1879 len -= mc_write (file, (char *) buf, end - start);
1880 start = end;
1882 g_free (buf);
1884 mc_close (file);
1885 if (len)
1886 return 0;
1887 return 1;
1890 /* copies a block to clipboard file */
1891 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1893 int ret;
1894 gchar *tmp;
1895 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1896 ret = edit_save_block (edit, tmp, start, finish);
1897 g_free(tmp);
1898 return ret;
1902 void edit_paste_from_history (WEdit *edit)
1904 (void) edit;
1905 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1908 int edit_copy_to_X_buf_cmd (WEdit * edit)
1910 long start_mark, end_mark;
1911 if (eval_marks (edit, &start_mark, &end_mark))
1912 return 0;
1913 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1914 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1915 return 1;
1917 edit_mark_cmd (edit, 1);
1918 return 0;
1921 int edit_cut_to_X_buf_cmd (WEdit * edit)
1923 long start_mark, end_mark;
1924 if (eval_marks (edit, &start_mark, &end_mark))
1925 return 0;
1926 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1927 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1928 return 1;
1930 edit_block_delete_cmd (edit);
1931 edit_mark_cmd (edit, 1);
1932 return 0;
1935 void edit_paste_from_X_buf_cmd (WEdit * edit)
1937 gchar *tmp;
1938 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1939 edit_insert_file (edit, tmp);
1940 g_free(tmp);
1945 * Ask user for the line and go to that line.
1946 * Negative numbers mean line from the end (i.e. -1 is the last line).
1948 void
1949 edit_goto_cmd (WEdit *edit)
1951 char *f;
1952 static long line = 0; /* line as typed, saved as default */
1953 long l;
1954 char *error;
1955 char s[32];
1957 g_snprintf (s, sizeof (s), "%ld", line);
1958 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1959 line ? s : "");
1960 if (!f)
1961 return;
1963 if (!*f) {
1964 g_free (f);
1965 return;
1968 l = strtol (f, &error, 0);
1969 if (*error) {
1970 g_free (f);
1971 return;
1974 line = l;
1975 if (l < 0)
1976 l = edit->total_lines + l + 2;
1977 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
1978 edit_move_to_line (edit, l - 1);
1979 edit->force |= REDRAW_COMPLETELY;
1980 g_free (f);
1984 /* Return 1 on success */
1986 edit_save_block_cmd (WEdit *edit)
1988 long start_mark, end_mark;
1989 char *exp, *tmp;
1991 if (eval_marks (edit, &start_mark, &end_mark))
1992 return 1;
1994 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1995 exp =
1996 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
1997 MC_HISTORY_EDIT_SAVE_BLOCK,
1998 tmp);
1999 g_free(tmp);
2000 edit_push_action (edit, KEY_PRESS + edit->start_display);
2001 if (exp) {
2002 if (!*exp) {
2003 g_free (exp);
2004 return 0;
2005 } else {
2006 if (edit_save_block (edit, exp, start_mark, end_mark)) {
2007 g_free (exp);
2008 edit->force |= REDRAW_COMPLETELY;
2009 return 1;
2010 } else {
2011 g_free (exp);
2012 edit_error_dialog (_(" Save Block "),
2013 get_sys_error (_
2014 (" Cannot save file. ")));
2018 edit->force |= REDRAW_COMPLETELY;
2019 return 0;
2023 /* returns 1 on success */
2025 edit_insert_file_cmd (WEdit *edit)
2027 gchar *tmp;
2028 char *exp;
2030 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2031 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2032 MC_HISTORY_EDIT_INSERT_FILE,
2033 tmp);
2034 g_free(tmp);
2035 edit_push_action (edit, KEY_PRESS + edit->start_display);
2036 if (exp) {
2037 if (!*exp) {
2038 g_free (exp);
2039 return 0;
2040 } else {
2041 if (edit_insert_file (edit, exp)) {
2042 g_free (exp);
2043 edit->force |= REDRAW_COMPLETELY;
2044 return 1;
2045 } else {
2046 g_free (exp);
2047 edit_error_dialog (_(" Insert File "),
2048 get_sys_error (_
2049 (" Cannot insert file. ")));
2053 edit->force |= REDRAW_COMPLETELY;
2054 return 0;
2057 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2058 int edit_sort_cmd (WEdit * edit)
2060 static char *old = 0;
2061 char *exp, *tmp;
2062 long start_mark, end_mark;
2063 int e;
2065 if (eval_marks (edit, &start_mark, &end_mark)) {
2066 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2067 return 0;
2070 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2071 edit_save_block (edit, tmp, start_mark, end_mark);
2072 g_free(tmp);
2074 exp = input_dialog (_(" Run Sort "),
2075 _(" Enter sort options (see manpage) separated by whitespace: "),
2076 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2078 if (!exp)
2079 return 1;
2080 g_free (old);
2081 old = exp;
2082 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2083 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2084 e = system (tmp);
2085 g_free(tmp);
2086 if (e) {
2087 if (e == -1 || e == 127) {
2088 edit_error_dialog (_(" Sort "),
2089 get_sys_error (_(" Cannot execute sort command ")));
2090 } else {
2091 char q[8];
2092 sprintf (q, "%d ", e);
2093 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2094 edit_error_dialog (_(" Sort "), tmp);
2095 g_free(tmp);
2097 return -1;
2100 edit->force |= REDRAW_COMPLETELY;
2102 if (edit_block_delete_cmd (edit))
2103 return 1;
2104 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2105 edit_insert_file (edit, tmp);
2106 g_free(tmp);
2107 return 0;
2111 * Ask user for a command, execute it and paste its output back to the
2112 * editor.
2115 edit_ext_cmd (WEdit *edit)
2117 char *exp, *tmp;
2118 int e;
2120 exp =
2121 input_dialog (_("Paste output of external command"),
2122 _("Enter shell command(s):"),
2123 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2125 if (!exp)
2126 return 1;
2128 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2129 e = system (tmp);
2130 g_free(tmp);
2131 g_free (exp);
2133 if (e) {
2134 edit_error_dialog (_("External command"),
2135 get_sys_error (_("Cannot execute command")));
2136 return -1;
2139 edit->force |= REDRAW_COMPLETELY;
2140 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2141 edit_insert_file (edit, tmp);
2142 g_free(tmp);
2143 return 0;
2146 /* if block is 1, a block must be highlighted and the shell command
2147 processes it. If block is 0 the shell command is a straight system
2148 command, that just produces some output which is to be inserted */
2149 void
2150 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2152 long start_mark, end_mark;
2153 char buf[BUFSIZ];
2154 FILE *script_home = NULL;
2155 FILE *script_src = NULL;
2156 FILE *block_file = NULL;
2157 gchar *o, *h, *b, *tmp;
2158 char *quoted_name = NULL;
2160 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2161 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2162 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2164 if (!(script_home = fopen (h, "r"))) {
2165 if (!(script_home = fopen (h, "w"))) {
2166 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2167 edit_error_dialog ("", get_sys_error (tmp));
2168 g_free(tmp);
2169 goto edit_block_process_cmd__EXIT;
2171 if (!(script_src = fopen (o, "r"))) {
2172 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2173 if (!(script_src = fopen (o, "r"))) {
2174 fclose (script_home);
2175 unlink (h);
2176 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2177 edit_error_dialog ("", get_sys_error (tmp));
2178 g_free(tmp);
2179 goto edit_block_process_cmd__EXIT;
2182 while (fgets (buf, sizeof (buf), script_src))
2183 fputs (buf, script_home);
2184 if (fclose (script_home)) {
2185 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2186 edit_error_dialog ("", get_sys_error (tmp));
2187 g_free(tmp);
2188 goto edit_block_process_cmd__EXIT;
2190 chmod (h, 0700);
2191 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2192 edit_error_dialog ("", get_sys_error (tmp));
2193 g_free(tmp);
2196 open_error_pipe ();
2198 if (block) { /* for marked block run indent formatter */
2199 if (eval_marks (edit, &start_mark, &end_mark)) {
2200 edit_error_dialog (_("Process block"),
2202 (" You must first highlight a block of text. "));
2203 goto edit_block_process_cmd__EXIT;
2205 edit_save_block (edit, b, start_mark, end_mark);
2206 quoted_name = name_quote (edit->filename, 0);
2208 * Run script.
2209 * Initial space is to avoid polluting bash history.
2210 * Arguments:
2211 * $1 - name of the edited file (to check its extension etc).
2212 * $2 - file containing the current block.
2213 * $3 - file where error messages should be put
2214 * (for compatibility with old scripts).
2216 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2217 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2218 system (tmp);
2219 g_free(tmp);
2220 } else {
2222 * No block selected, just execute the command for the file.
2223 * Arguments:
2224 * $1 - name of the edited file.
2226 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2227 quoted_name, (char *) NULL);
2228 system (tmp);
2229 g_free(tmp);
2231 g_free (quoted_name);
2232 close_error_pipe (D_NORMAL, NULL);
2234 edit_refresh_cmd (edit);
2235 edit->force |= REDRAW_COMPLETELY;
2237 /* insert result block */
2238 if (block) {
2239 if (edit_block_delete_cmd (edit))
2240 goto edit_block_process_cmd__EXIT;
2241 edit_insert_file (edit, b);
2242 if ((block_file = fopen (b, "w")))
2243 fclose (block_file);
2244 goto edit_block_process_cmd__EXIT;
2246 edit_block_process_cmd__EXIT:
2247 g_free(b);
2248 g_free(h);
2249 g_free(o);
2250 return;
2253 /* prints at the cursor */
2254 /* returns the number of chars printed */
2255 int edit_print_string (WEdit * e, const char *s)
2257 int i = 0;
2258 while (s[i])
2259 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2260 e->force |= REDRAW_COMPLETELY;
2261 edit_update_screen (e);
2262 return i;
2266 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2268 FILE *p = 0;
2269 char *s;
2271 to = name_quote (to, 0);
2272 subject = name_quote (subject, 0);
2273 cc = name_quote (cc, 0);
2274 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2275 g_free (to);
2276 g_free (subject);
2277 g_free (cc);
2279 if (s) {
2280 p = popen (s, "w");
2281 g_free (s);
2284 if (p) {
2285 long i;
2286 for (i = 0; i < edit->last_byte; i++)
2287 fputc (edit_get_byte (edit, i), p);
2288 pclose (p);
2292 #define MAIL_DLG_HEIGHT 12
2294 void edit_mail_dialog (WEdit * edit)
2296 char *tmail_to;
2297 char *tmail_subject;
2298 char *tmail_cc;
2300 static char *mail_cc_last = 0;
2301 static char *mail_subject_last = 0;
2302 static char *mail_to_last = 0;
2304 QuickWidget quick_widgets[] =
2306 /* 0 */ QUICK_BUTTON (6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), B_CANCEL, NULL),
2307 /* 1 */ QUICK_BUTTON (2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), B_ENTER, NULL),
2308 /* 2 */ QUICK_INPUT (3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input", &tmail_cc),
2309 /* 3 */ QUICK_LABEL (2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to")),
2310 /* 4 */ QUICK_INPUT (3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-2", &tmail_subject),
2311 /* 5 */ QUICK_LABEL (2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject")),
2312 /* 6 */ QUICK_INPUT (3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, "mail-dlg-input-3", &tmail_to),
2313 /* 7 */ QUICK_LABEL (2, 50, 3, MAIL_DLG_HEIGHT, N_(" To")),
2314 /* 8 */ QUICK_LABEL (2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>")),
2315 QUICK_END
2318 QuickDialog Quick_input =
2320 50, MAIL_DLG_HEIGHT, -1, -1, N_(" Mail "),
2321 "[Input Line Keys]", quick_widgets, FALSE
2324 quick_widgets[2].u.input.text = mail_cc_last ? mail_cc_last : "";
2325 quick_widgets[4].u.input.text = mail_subject_last ? mail_subject_last : "";
2326 quick_widgets[6].u.input.text = mail_to_last ? mail_to_last : "";
2328 if (quick_dialog (&Quick_input) != B_CANCEL) {
2329 g_free (mail_cc_last);
2330 g_free (mail_subject_last);
2331 g_free (mail_to_last);
2332 mail_cc_last = tmail_cc;
2333 mail_subject_last = tmail_subject;
2334 mail_to_last = tmail_to;
2335 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2340 /*******************/
2341 /* Word Completion */
2342 /*******************/
2344 static gboolean is_break_char(char c)
2346 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2349 /* find first character of current word */
2350 static int edit_find_word_start (WEdit *edit, long *word_start, gsize *word_len)
2352 int c, last;
2353 gsize i;
2355 /* return if at begin of file */
2356 if (edit->curs1 <= 0)
2357 return 0;
2359 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2360 /* return if not at end or in word */
2361 if (is_break_char(c))
2362 return 0;
2364 /* search start of word to be completed */
2365 for (i = 2;; i++) {
2366 /* return if at begin of file */
2367 if (edit->curs1 - i < 0)
2368 return 0;
2370 last = c;
2371 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2373 if (is_break_char(c)) {
2374 /* return if word starts with digit */
2375 if (isdigit (last))
2376 return 0;
2378 *word_start = edit->curs1 - (i - 1); /* start found */
2379 *word_len = i - 1;
2380 break;
2383 /* success */
2384 return 1;
2387 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2389 /* collect the possible completions */
2390 static gsize
2391 edit_collect_completions (WEdit *edit, long start, gsize word_len,
2392 char *match_expr, struct selection *compl,
2393 gsize *num)
2395 gsize len = 0;
2396 gsize max_len = 0;
2397 gsize i;
2398 int skip;
2399 GString *temp;
2400 mc_search_t *srch;
2402 long last_byte;
2404 srch = mc_search_new(match_expr, -1);
2405 if (srch == NULL)
2406 return 0;
2408 if (mc_config_get_bool(mc_main_config, CONFIG_APP_SECTION, "editor_wordcompletion_collect_entire_file", 0)){
2409 last_byte = edit->last_byte;
2410 } else {
2411 last_byte = start;
2414 srch->search_type = MC_SEARCH_T_REGEX;
2415 srch->is_case_sentitive = TRUE;
2416 srch->search_fn = edit_search_cmd_callback;
2418 /* collect max MAX_WORD_COMPLETIONS completions */
2419 start = -1;
2420 while (1) {
2421 /* get next match */
2422 if (mc_search_run (srch, (void *) edit, start+1, last_byte, &len) == FALSE)
2423 break;
2424 start = srch->normal_offset;
2426 /* add matched completion if not yet added */
2427 temp = g_string_new("");
2428 for (i = 0; i < len; i++){
2429 skip = edit_get_byte(edit, start+i);
2430 if (isspace(skip))
2431 continue;
2432 g_string_append_c (temp, skip);
2435 skip = 0;
2437 for (i = 0; i < (gsize) *num; i++) {
2438 if (strncmp
2440 (char *) &compl[i].text[word_len],
2441 (char *) &temp->str[word_len],
2442 max (len, compl[i].len) - (gsize)word_len
2443 ) == 0) {
2444 struct selection this = compl[i];
2445 for (++i; i < *num; i++) {
2446 compl[i - 1] = compl[i];
2448 compl[*num - 1] = this;
2449 skip = 1;
2450 break; /* skip it, already added */
2453 if (skip) {
2454 g_string_free(temp, TRUE);
2455 continue;
2457 if (*num == MAX_WORD_COMPLETIONS && MAX_WORD_COMPLETIONS) {
2458 g_free(compl[0].text);
2459 for (i = 1; i < *num; i++) {
2460 compl[i - 1] = compl[i];
2462 (*num)--;
2464 #ifdef HAVE_CHARSET
2466 GString *recoded;
2467 recoded = str_convert_to_display (temp->str);
2469 if (recoded && recoded->len){
2470 g_string_free(temp,TRUE);
2471 temp = recoded;
2472 } else
2473 g_string_free(recoded , TRUE);
2475 #endif
2476 compl[*num].text = temp->str;
2477 compl[*num].len = temp->len;
2478 (*num)++;
2479 start += len;
2480 g_string_free(temp, FALSE);
2482 /* note the maximal length needed for the completion dialog */
2483 if (len > max_len)
2484 max_len = len;
2486 mc_search_free(srch);
2487 return max_len;
2491 * Complete current word using regular expression search
2492 * backwards beginning at the current cursor position.
2494 void
2495 edit_complete_word_cmd (WEdit *edit)
2497 gsize i, max_len, word_len = 0, num_compl = 0;
2498 long word_start = 0;
2499 unsigned char *bufpos;
2500 char *match_expr;
2501 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2503 /* search start of word to be completed */
2504 if (!edit_find_word_start (edit, &word_start, &word_len))
2505 return;
2507 /* prepare match expression */
2508 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2509 [word_start & M_EDIT_BUF_SIZE];
2511 /* match_expr = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */
2512 match_expr = g_strdup_printf ("(^|\\s+|\\b)%.*s[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+", word_len, bufpos);
2514 /* collect the possible completions */
2515 /* start search from begin to end of file */
2516 max_len =
2517 edit_collect_completions (edit, word_start, word_len, match_expr,
2518 (struct selection *) &compl, &num_compl);
2520 if (num_compl > 0) {
2521 /* insert completed word if there is only one match */
2522 if (num_compl == 1) {
2523 for (i = word_len; i < compl[0].len; i++)
2524 edit_insert (edit, *(compl[0].text + i));
2526 /* more than one possible completion => ask the user */
2527 else {
2528 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2529 /* !!! pressed again the selection dialog pops up, but that !!! */
2530 /* !!! seems to require a further internal state !!! */
2531 /*tty_beep (); */
2533 /* let the user select the preferred completion */
2534 editcmd_dialog_completion_show (edit, max_len, word_len,
2535 (struct selection *) &compl,
2536 num_compl);
2540 g_free (match_expr);
2541 /* release memory before return */
2542 for (i = 0; i < num_compl; i++)
2543 g_free (compl[i].text);
2546 void
2547 edit_select_codepage_cmd (WEdit *edit)
2549 #ifdef HAVE_CHARSET
2550 const char *cp_id = NULL;
2551 if (do_select_codepage ()) {
2552 cp_id = get_codepage_id (source_codepage >= 0 ?
2553 source_codepage : display_codepage);
2555 if (cp_id != NULL) {
2556 GIConv conv;
2557 conv = str_crt_conv_from (cp_id);
2558 if (conv != INVALID_CONV) {
2559 if (edit->converter != str_cnv_from_term)
2560 str_close_conv (edit->converter);
2561 edit->converter = conv;
2565 if (cp_id != NULL)
2566 edit->utf8 = str_isutf8 (cp_id);
2569 edit->force = REDRAW_COMPLETELY;
2570 edit_refresh_cmd (edit);
2571 #else
2572 (void) edit;
2573 #endif
2576 void
2577 edit_insert_literal_cmd (WEdit *edit)
2579 int char_for_insertion =
2580 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2581 _(" Press any key: "), 0);
2582 edit_execute_key_command (edit, -1,
2583 ascii_alpha_to_cntrl (char_for_insertion));
2586 void
2587 edit_execute_macro_cmd (WEdit *edit)
2589 int command =
2590 CK_Macro (editcmd_dialog_raw_key_query
2591 (_(" Execute Macro "), _(" Press macro hotkey: "),
2592 1));
2593 if (command == CK_Macro (0))
2594 command = CK_Insert_Char;
2596 edit_execute_key_command (edit, command, -1);
2599 void
2600 edit_begin_end_macro_cmd (WEdit *edit)
2602 /* edit is a pointer to the widget */
2603 if (edit) {
2604 unsigned long command = edit->macro_i < 0
2605 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2606 edit_execute_key_command (edit, command, -1);
2611 edit_load_forward_cmd (WEdit *edit)
2613 if (edit->modified) {
2614 if (edit_query_dialog2
2615 (_("Warning"),
2616 _(" Current text was modified without a file save. \n"
2617 " Continue discards these changes. "), _("C&ontinue"),
2618 _("&Cancel"))) {
2619 edit->force |= REDRAW_COMPLETELY;
2620 return 0;
2623 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2624 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2625 return 1;
2627 edit_stack_iterator++;
2628 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2629 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2630 edit_history_moveto[edit_stack_iterator].line);
2631 return 0;
2632 } else {
2633 return 1;
2635 } else {
2636 return 1;
2641 edit_load_back_cmd (WEdit *edit)
2643 if (edit->modified) {
2644 if (edit_query_dialog2
2645 (_("Warning"),
2646 _(" Current text was modified without a file save. \n"
2647 " Continue discards these changes. "), _("C&ontinue"),
2648 _("&Cancel"))) {
2649 edit->force |= REDRAW_COMPLETELY;
2650 return 0;
2653 if ( edit_stack_iterator > 0 ) {
2654 edit_stack_iterator--;
2655 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2656 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2657 edit_history_moveto[edit_stack_iterator].line);
2658 return 0;
2659 } else {
2660 return 1;
2662 } else {
2663 return 1;
2667 void
2668 edit_get_match_keyword_cmd (WEdit *edit)
2670 gsize word_len = 0, max_len = 0;
2671 int num_def = 0;
2672 int i;
2673 long word_start = 0;
2674 unsigned char *bufpos;
2675 char *match_expr;
2676 char *path = NULL;
2677 char *ptr = NULL;
2678 char *tagfile = NULL;
2680 etags_hash_t def_hash[MAX_DEFINITIONS];
2682 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2683 def_hash[i].filename = NULL;
2686 /* search start of word to be completed */
2687 if (!edit_find_word_start (edit, &word_start, &word_len))
2688 return;
2690 /* prepare match expression */
2691 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2692 [word_start & M_EDIT_BUF_SIZE];
2693 match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
2695 ptr = g_get_current_dir ();
2696 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2697 g_free (ptr);
2699 /* Recursive search file 'TAGS' in parent dirs */
2700 do {
2701 ptr = g_path_get_dirname (path);
2702 g_free(path); path = ptr;
2703 g_free (tagfile);
2704 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2705 if ( exist_file (tagfile) )
2706 break;
2707 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2709 if (tagfile){
2710 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2711 g_free (tagfile);
2713 g_free (path);
2715 max_len = MAX_WIDTH_DEF_DIALOG;
2716 word_len = 0;
2717 if ( num_def > 0 ) {
2718 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2719 (etags_hash_t *) &def_hash,
2720 num_def);
2722 g_free (match_expr);
2725 void
2726 edit_move_block_to_right (WEdit * edit)
2728 long start_mark, end_mark;
2729 long cur_bol, start_bol;
2731 if ( eval_marks (edit, &start_mark, &end_mark) )
2732 return;
2734 start_bol = edit_bol (edit, start_mark);
2735 cur_bol = edit_bol (edit, end_mark - 1);
2736 do {
2737 edit_cursor_move (edit, cur_bol - edit->curs1);
2738 if ( option_fill_tabs_with_spaces ) {
2739 if ( option_fake_half_tabs ) {
2740 insert_spaces_tab (edit, 1);
2741 } else {
2742 insert_spaces_tab (edit, 0);
2744 } else {
2745 edit_insert (edit, '\t');
2747 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2748 if ( cur_bol == 0 ) {
2749 break;
2751 cur_bol = edit_bol (edit, cur_bol - 1);
2752 } while (cur_bol >= start_bol) ;
2753 edit->force |= REDRAW_PAGE;
2756 void
2757 edit_move_block_to_left (WEdit * edit)
2759 long start_mark, end_mark;
2760 long cur_bol, start_bol;
2761 int i, del_tab_width;
2762 int next_char;
2764 if ( eval_marks (edit, &start_mark, &end_mark) )
2765 return;
2767 start_bol = edit_bol (edit, start_mark);
2768 cur_bol = edit_bol (edit, end_mark - 1);
2769 do {
2770 edit_cursor_move (edit, cur_bol - edit->curs1);
2771 if (option_fake_half_tabs) {
2772 del_tab_width = HALF_TAB_SIZE;
2773 } else {
2774 del_tab_width = option_tab_spacing;
2776 next_char = edit_get_byte (edit, edit->curs1);
2777 if ( next_char == '\t' ) {
2778 edit_delete (edit, 1);
2779 } else if ( next_char == ' ' ) {
2780 for (i = 1; i <= del_tab_width; i++) {
2781 if ( next_char == ' ' ) {
2782 edit_delete (edit, 1);
2784 next_char = edit_get_byte (edit, edit->curs1);
2787 if ( cur_bol == 0 ) {
2788 break;
2790 cur_bol = edit_bol (edit, cur_bol - 1);
2791 } while (cur_bol >= start_bol) ;
2792 edit->force |= REDRAW_PAGE;