Added field lb (kind of line break) into WEdit struct
[midnight-commander.git] / edit / editcmd.c
blob759621529e375704741c05de96a0536c1a3b7e7d
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 */
63 #include "../edit/edit-impl.h"
64 #include "../edit/edit.h"
65 #include "../edit/editlock.h"
66 #include "../edit/editcmddef.h"
67 #include "../edit/edit-widget.h"
68 #include "../edit/editcmd_dialogs.h"
69 #include "../edit/etags.h"
71 /* globals: */
73 /* search and replace: */
74 static int search_create_bookmark = 0;
75 /* static int search_in_all_charsets = 0; */
77 /* queries on a save */
78 int edit_confirm_save = 1;
80 static int edit_save_cmd (WEdit *edit);
81 static unsigned char *edit_get_block (WEdit *edit, long start,
82 long finish, int *l);
84 static void
85 edit_search_cmd_search_create_bookmark(WEdit * edit)
87 int found = 0, books = 0;
88 int l = 0, l_last = -1;
89 long q = 0;
90 gsize len = 0;
92 for (;;) {
93 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
94 break;
96 found++;
97 l += edit_count_lines (edit, q, edit->search->normal_offset);
98 if (l != l_last) {
99 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
100 books++;
102 l_last = l;
103 q = edit->search->normal_offset + 1;
106 if (found) {
107 /* in response to number of bookmarks added because of string being found %d times */
108 message (D_NORMAL, _("Search"), _(" %d items found, %d bookmarks added "), found, books);
109 } else {
110 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
114 static int
115 edit_search_cmd_callback(const void *user_data, gsize char_offset)
117 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
120 void edit_help_cmd (WEdit * edit)
122 interactive_display (NULL, "[Internal File Editor]");
123 edit->force |= REDRAW_COMPLETELY;
126 void
127 edit_refresh_cmd (WEdit * edit)
129 #ifdef HAVE_SLANG
130 int color;
132 edit_get_syntax_color (edit, -1, &color);
133 tty_touch_screen ();
134 mc_refresh ();
135 #else
136 clr_scr ();
137 repaint_screen ();
138 #endif /* !HAVE_SLANG */
139 tty_keypad (TRUE);
142 /* If 0 (quick save) then a) create/truncate <filename> file,
143 b) save to <filename>;
144 if 1 (safe save) then a) save to <tempnam>,
145 b) rename <tempnam> to <filename>;
146 if 2 (do backups) then a) save to <tempnam>,
147 b) rename <filename> to <filename.backup_ext>,
148 c) rename <tempnam> to <filename>. */
150 /* returns 0 on error, -1 on abort */
151 static int
152 edit_save_file (WEdit *edit, const char *filename)
154 char *p;
155 gchar *tmp;
156 long filelen = 0;
157 char *savename = 0;
158 gchar *real_filename;
159 int this_save_mode, fd = -1;
161 if (!filename)
162 return 0;
163 if (!*filename)
164 return 0;
166 if (*filename != PATH_SEP && edit->dir) {
167 real_filename = concat_dir_and_file (edit->dir, filename);
168 } else {
169 real_filename = g_strdup(filename);
172 this_save_mode = option_save_mode;
173 if (this_save_mode != EDIT_QUICK_SAVE) {
174 if (!vfs_file_is_local (real_filename) ||
175 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
177 * The file does not exists yet, so no safe save or
178 * backup are necessary.
180 this_save_mode = EDIT_QUICK_SAVE;
182 if (fd != -1)
183 mc_close (fd);
186 if (this_save_mode == EDIT_QUICK_SAVE &&
187 !edit->skip_detach_prompt) {
188 int rv;
189 struct stat sb;
191 rv = mc_stat (real_filename, &sb);
192 if (rv == 0 && sb.st_nlink > 1) {
193 rv = edit_query_dialog3 (_("Warning"),
194 _(" File has hard-links. Detach before saving? "),
195 _("&Yes"), _("&No"), _("&Cancel"));
196 switch (rv) {
197 case 0:
198 this_save_mode = EDIT_SAFE_SAVE;
199 /* fallthrough */
200 case 1:
201 edit->skip_detach_prompt = 1;
202 break;
203 default:
204 g_free(real_filename);
205 return -1;
209 /* Prevent overwriting changes from other editor sessions. */
210 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
212 /* The default action is "Cancel". */
213 query_set_sel(1);
215 rv = edit_query_dialog2 (
216 _("Warning"),
217 _("The file has been modified in the meantime. Save anyway?"),
218 _("&Yes"),
219 _("&Cancel"));
220 if (rv != 0){
221 g_free(real_filename);
222 return -1;
227 if (this_save_mode != EDIT_QUICK_SAVE) {
228 char *savedir, *saveprefix;
229 const char *slashpos;
230 slashpos = strrchr (real_filename, PATH_SEP);
231 if (slashpos) {
232 savedir = g_strdup (real_filename);
233 savedir[slashpos - real_filename + 1] = '\0';
234 } else
235 savedir = g_strdup (".");
236 saveprefix = concat_dir_and_file (savedir, "cooledit");
237 g_free (savedir);
238 fd = mc_mkstemps (&savename, saveprefix, NULL);
239 g_free (saveprefix);
240 if (!savename){
241 g_free(real_filename);
242 return 0;
244 /* FIXME:
245 * Close for now because mc_mkstemps use pure open system call
246 * to create temporary file and it needs to be reopened by
247 * VFS-aware mc_open().
249 close (fd);
250 } else
251 savename = g_strdup (real_filename);
253 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
254 mc_chmod (savename, edit->stat1.st_mode);
256 if ((fd =
257 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
258 edit->stat1.st_mode)) == -1)
259 goto error_save;
261 /* pipe save */
262 if ((p = edit_get_write_filter (savename, real_filename))) {
263 FILE *file;
265 mc_close (fd);
266 file = (FILE *) popen (p, "w");
268 if (file) {
269 filelen = edit_write_stream (edit, file);
270 #if 1
271 pclose (file);
272 #else
273 if (pclose (file) != 0) {
274 tmp = g_strconcat (_(" Error writing to pipe: "),
275 p, " ", (char *) NULL);
276 edit_error_dialog (_("Error"), tmp);
277 g_free(tmp);
278 g_free (p);
279 goto error_save;
281 #endif
282 } else {
283 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
284 p, " ", (char *) NULL);
286 edit_error_dialog (_("Error"),
287 get_sys_error (tmp));
288 g_free (p);
289 g_free(tmp);
290 goto error_save;
292 g_free (p);
293 } else if (edit->lb == LB_ASIS) { /* do not change line breaks */
294 long buf;
295 buf = 0;
296 filelen = edit->last_byte;
297 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
298 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
299 != EDIT_BUF_SIZE) {
300 mc_close (fd);
301 goto error_save;
303 buf++;
305 if (mc_write
306 (fd, (char *) edit->buffers1[buf],
307 edit->curs1 & M_EDIT_BUF_SIZE) !=
308 (edit->curs1 & M_EDIT_BUF_SIZE)) {
309 filelen = -1;
310 } else if (edit->curs2) {
311 edit->curs2--;
312 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
313 if (mc_write
314 (fd,
315 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
316 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
317 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
318 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
319 filelen = -1;
320 } else {
321 while (--buf >= 0) {
322 if (mc_write
323 (fd, (char *) edit->buffers2[buf],
324 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
325 filelen = -1;
326 break;
330 edit->curs2++;
332 if (mc_close (fd))
333 goto error_save;
335 /* Update the file information, especially the mtime. */
336 if (mc_stat (savename, &edit->stat1) == -1)
337 goto error_save;
338 } else { /* change line breaks */
339 FILE *file;
341 mc_close (fd);
343 file = (FILE *) fopen (savename, "w");
345 if (file) {
346 filelen = edit_write_stream (edit, file);
347 fclose (file);
348 } else {
349 char *msg;
351 msg = g_strdup_printf (_(" Cannot open file for writing: %s "), savename);
352 edit_error_dialog (_("Error"), msg);
353 g_free (msg);
354 goto error_save;
358 if (filelen != edit->last_byte)
359 goto error_save;
361 if (this_save_mode == EDIT_DO_BACKUP) {
362 assert (option_backup_ext != NULL);
363 tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
364 if (mc_rename (real_filename, tmp) == -1){
365 g_free(tmp);
366 goto error_save;
370 if (this_save_mode != EDIT_QUICK_SAVE)
371 if (mc_rename (savename, real_filename) == -1)
372 goto error_save;
373 g_free (savename);
374 g_free(real_filename);
375 return 1;
376 error_save:
377 /* FIXME: Is this safe ?
378 * if (this_save_mode != EDIT_QUICK_SAVE)
379 * mc_unlink (savename);
381 g_free(real_filename);
382 g_free (savename);
383 return 0;
386 void menu_save_mode_cmd (void)
388 #define DLG_X 38
389 #define DLG_Y 10
390 static char *str_result;
391 static int save_mode_new;
392 static const char *str[] =
394 N_("Quick save "),
395 N_("Safe save "),
396 N_("Do backups -->")};
398 static QuickWidget widgets[] =
400 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
401 B_CANCEL, 0, 0, NULL, NULL, NULL},
402 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
403 B_ENTER, 0, 0, NULL, NULL, NULL},
404 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
405 0, 0, &str_result, "edit-backup-ext", NULL, NULL},
406 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
407 0, 0, 0, NULL, NULL, NULL},
408 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
409 0, &save_mode_new, (char **) str, NULL, NULL, NULL},
410 NULL_QuickWidget};
411 static QuickDialog dialog =
412 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
413 widgets, 0};
414 static int i18n_flag = 0;
416 if (!i18n_flag) {
417 size_t i;
418 size_t maxlen = 0;
419 int dlg_x;
420 size_t l1;
422 /* OK/Cancel buttons */
423 l1 = str_term_width1 (_(widgets[0].text)) + str_term_width1 (_(widgets[1].text)) + 5;
424 maxlen = max (maxlen, l1);
426 for (i = 0; i < 3; i++ ) {
427 str[i] = _(str[i]);
428 maxlen = max (maxlen, (size_t) str_term_width1 (str[i]) + 7);
430 i18n_flag = 1;
432 dlg_x = maxlen + str_term_width1 (_(widgets[3].text)) + 5 + 1;
433 widgets[2].hotkey_pos = str_term_width1 (_(widgets[3].text)); /* input field length */
434 dlg_x = min (COLS, dlg_x);
435 dialog.xlen = dlg_x;
437 i = (dlg_x - l1)/3;
438 widgets[1].relative_x = i;
439 widgets[0].relative_x = i + str_term_width1 (_(widgets[1].text)) + i + 4;
441 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
443 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
444 widgets[i].x_divisions = dlg_x;
447 assert (option_backup_ext != NULL);
448 widgets[2].text = option_backup_ext;
449 widgets[4].value = option_save_mode;
450 if (quick_dialog (&dialog) != B_ENTER)
451 return;
452 option_save_mode = save_mode_new;
454 g_free (option_backup_ext);
455 option_backup_ext = str_result;
456 str_result = NULL;
459 void
460 edit_set_filename (WEdit *edit, const char *f)
462 g_free (edit->filename);
463 if (!f)
464 f = "";
465 edit->filename = g_strdup (f);
466 if (edit->dir == NULL && *f != PATH_SEP)
467 #ifdef USE_VFS
468 edit->dir = g_strdup (vfs_get_current_dir ());
469 #else
470 edit->dir = g_get_current_dir ();
471 #endif
474 static char *
475 edit_get_save_file_as (WEdit *edit)
477 #define DLG_WIDTH 64
478 #define DLG_HEIGHT 14
480 char *filename = edit->filename;
482 const char *lb_names[LB_NAMES] =
484 N_("&Do not change"),
485 N_("&Unix format (LF)"),
486 N_("&Windows/DOS format (CR LF)"),
487 N_("&Macintosh format (LF)")
490 static LineBreaks cur_lb = LB_ASIS;
492 QuickWidget quick_widgets[] =
494 {quick_button, 6, 10, DLG_HEIGHT - 3, DLG_HEIGHT,
495 N_("&Cancel"), 0, B_CANCEL, NULL, NULL, NULL, NULL, NULL},
496 {quick_button, 2, 10, DLG_HEIGHT - 3, DLG_HEIGHT,
497 N_("&OK"), 0, B_ENTER, NULL, NULL, NULL, NULL, NULL},
498 {quick_radio, 5, DLG_WIDTH, DLG_HEIGHT - 8, DLG_HEIGHT, "",
499 LB_NAMES, cur_lb, (int *) &cur_lb, (char **) lb_names, NULL, NULL, NULL},
500 {quick_label, 3, DLG_WIDTH, DLG_HEIGHT - 9, DLG_HEIGHT,
501 N_("Change line breaks to:"), 0, 0, NULL, NULL, NULL, NULL, NULL},
502 {quick_input, 3, DLG_WIDTH, DLG_HEIGHT - 11, DLG_HEIGHT,
503 filename, 58, 0, 0, &filename, "save-file-as", NULL, NULL},
504 {quick_label, 2, DLG_WIDTH, DLG_HEIGHT - 12, DLG_HEIGHT,
505 N_(" Enter file name: "), 0, 0, NULL, NULL, NULL, NULL, NULL},
506 NULL_QuickWidget
509 QuickDialog Quick_options =
511 DLG_WIDTH, DLG_HEIGHT, -1, -1, N_(" Save As "), "", quick_widgets, 0
514 if (quick_dialog (&Quick_options) != B_CANCEL)
516 edit->lb = cur_lb;
517 return filename;
520 return NULL;
522 #undef DLG_WIDTH
523 #undef DLG_HEIGHT
526 /* Here we want to warn the users of overwriting an existing file,
527 but only if they have made a change to the filename */
528 /* returns 1 on success */
530 edit_save_as_cmd (WEdit *edit)
532 /* This heads the 'Save As' dialog box */
533 char *exp;
534 int save_lock = 0;
535 int different_filename = 0;
537 exp = edit_get_save_file_as (edit);
538 edit_push_action (edit, KEY_PRESS + edit->start_display);
540 if (exp) {
541 if (!*exp) {
542 g_free (exp);
543 edit->force |= REDRAW_COMPLETELY;
544 return 0;
545 } else {
546 int rv;
547 if (strcmp (edit->filename, exp)) {
548 int file;
549 different_filename = 1;
550 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
551 /* the file exists */
552 mc_close (file);
553 /* Overwrite the current file or cancel the operation */
554 if (edit_query_dialog2
555 (_("Warning"),
556 _(" A file already exists with this name. "),
557 _("&Overwrite"), _("&Cancel"))) {
558 edit->force |= REDRAW_COMPLETELY;
559 g_free (exp);
560 return 0;
562 } else {
563 edit->stat1.st_mode |= S_IWUSR;
565 save_lock = edit_lock_file (exp);
566 } else {
567 /* filenames equal, check if already locked */
568 if (!edit->locked && !edit->delete_file)
569 save_lock = edit_lock_file (exp);
572 if (different_filename)
575 * Allow user to write into saved (under another name) file
576 * even if original file had r/o user permissions.
578 edit->stat1.st_mode |= S_IWRITE;
581 rv = edit_save_file (edit, exp);
582 switch (rv) {
583 case 1:
584 /* Succesful, so unlock both files */
585 if (different_filename) {
586 if (save_lock)
587 edit_unlock_file (exp);
588 if (edit->locked)
589 edit->locked = edit_unlock_file (edit->filename);
590 } else {
591 if (edit->locked || save_lock)
592 edit->locked = edit_unlock_file (edit->filename);
595 edit_set_filename (edit, exp);
596 if (edit->lb != LB_ASIS)
597 edit_reload(edit, exp);
598 g_free (exp);
599 edit->modified = 0;
600 edit->delete_file = 0;
601 if (different_filename)
602 edit_load_syntax (edit, NULL, option_syntax_type);
603 edit->force |= REDRAW_COMPLETELY;
604 return 1;
605 default:
606 edit_error_dialog (_(" Save As "),
607 get_sys_error (_
608 (" Cannot save file. ")));
609 /* fallthrough */
610 case -1:
611 /* Failed, so maintain modify (not save) lock */
612 if (save_lock)
613 edit_unlock_file (exp);
614 g_free (exp);
615 edit->force |= REDRAW_COMPLETELY;
616 return 0;
620 edit->force |= REDRAW_COMPLETELY;
621 return 0;
624 /* {{{ Macro stuff starts here */
626 /* creates a macro file if it doesn't exist */
627 static FILE *edit_open_macro_file (const char *r)
629 gchar *filename;
630 FILE *fd;
631 int file;
632 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
633 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
634 g_free(filename);
635 return 0;
637 close (file);
638 fd = fopen (filename, r);
639 g_free(filename);
640 return fd;
643 #define MAX_MACROS 1024
644 static int saved_macro[MAX_MACROS + 1];
645 static int saved_macros_loaded = 0;
648 This is just to stop the macro file be loaded over and over for keys
649 that aren't defined to anything. On slow systems this could be annoying.
651 static int
652 macro_exists (int k)
654 int i;
655 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
656 if (saved_macro[i] == k)
657 return i;
658 return -1;
661 /* returns 1 on error */
662 static int
663 edit_delete_macro (WEdit * edit, int k)
665 gchar *tmp, *tmp2;
666 struct macro macro[MAX_MACRO_LENGTH];
667 FILE *f, *g;
668 int s, i, n, j = 0;
670 (void) edit;
672 if (saved_macros_loaded)
673 if ((j = macro_exists (k)) < 0)
674 return 0;
675 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
676 g = fopen (tmp , "w");
677 g_free(tmp);
678 if (!g) {
679 edit_error_dialog (_(" Delete macro "),
680 get_sys_error (_(" Cannot open temp file ")));
681 return 1;
683 f = edit_open_macro_file ("r");
684 if (!f) {
685 edit_error_dialog (_(" Delete macro "),
686 get_sys_error (_(" Cannot open macro file ")));
687 fclose (g);
688 return 1;
690 for (;;) {
691 n = fscanf (f, ("key '%d 0': "), &s);
692 if (!n || n == EOF)
693 break;
694 n = 0;
695 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
696 n++;
697 fscanf (f, ";\n");
698 if (s != k) {
699 fprintf (g, ("key '%d 0': "), s);
700 for (i = 0; i < n; i++)
701 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
702 fprintf (g, ";\n");
705 fclose (f);
706 fclose (g);
707 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
708 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
709 if (rename ( tmp, tmp2) == -1) {
710 edit_error_dialog (_(" Delete macro "),
711 get_sys_error (_(" Cannot overwrite macro file ")));
712 g_free(tmp);
713 g_free(tmp2);
714 return 1;
716 g_free(tmp);
717 g_free(tmp2);
719 if (saved_macros_loaded)
720 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
721 return 0;
724 /* returns 0 on error */
725 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
727 FILE *f;
728 int s, i;
730 edit_push_action (edit, KEY_PRESS + edit->start_display);
731 s = editcmd_dialog_raw_key_query (_(" Save macro "),
732 _(" Press the macro's new hotkey: "), 1);
733 edit->force |= REDRAW_COMPLETELY;
734 if (s) {
735 if (edit_delete_macro (edit, s))
736 return 0;
737 f = edit_open_macro_file ("a+");
738 if (f) {
739 fprintf (f, ("key '%d 0': "), s);
740 for (i = 0; i < n; i++)
741 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
742 fprintf (f, ";\n");
743 fclose (f);
744 if (saved_macros_loaded) {
745 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
746 saved_macro[i] = s;
748 return 1;
749 } else
750 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
752 return 0;
755 void edit_delete_macro_cmd (WEdit * edit)
757 int command;
759 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
760 _ (" Press macro hotkey: "), 1);
762 if (!command)
763 return;
765 edit_delete_macro (edit, command);
768 /* return 0 on error */
769 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
771 FILE *f;
772 int s, i = 0, found = 0;
774 (void) edit;
776 if (saved_macros_loaded)
777 if (macro_exists (k) < 0)
778 return 0;
780 if ((f = edit_open_macro_file ("r"))) {
781 struct macro dummy;
782 do {
783 int u;
784 u = fscanf (f, ("key '%d 0': "), &s);
785 if (!u || u == EOF)
786 break;
787 if (!saved_macros_loaded)
788 saved_macro[i++] = s;
789 if (!found) {
790 *n = 0;
791 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
792 (*n)++;
793 } else {
794 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
796 fscanf (f, ";\n");
797 if (s == k)
798 found = 1;
799 } while (!found || !saved_macros_loaded);
800 if (!saved_macros_loaded) {
801 saved_macro[i] = 0;
802 saved_macros_loaded = 1;
804 fclose (f);
805 return found;
806 } else
807 edit_error_dialog (_(" Load macro "),
808 get_sys_error (_(" Cannot open macro file ")));
809 return 0;
812 /* }}} Macro stuff starts here */
814 /* returns 1 on success */
815 int edit_save_confirm_cmd (WEdit * edit)
817 gchar *f = NULL;
819 if (edit_confirm_save) {
820 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
821 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
822 g_free(f);
823 return 0;
825 g_free(f);
827 return edit_save_cmd (edit);
831 /* returns 1 on success */
832 static int
833 edit_save_cmd (WEdit *edit)
835 int res, save_lock = 0;
837 if (!edit->locked && !edit->delete_file)
838 save_lock = edit_lock_file (edit->filename);
839 res = edit_save_file (edit, edit->filename);
841 /* Maintain modify (not save) lock on failure */
842 if ((res > 0 && edit->locked) || save_lock)
843 edit->locked = edit_unlock_file (edit->filename);
845 /* On failure try 'save as', it does locking on its own */
846 if (!res)
847 return edit_save_as_cmd (edit);
848 edit->force |= REDRAW_COMPLETELY;
849 if (res > 0) {
850 edit->delete_file = 0;
851 edit->modified = 0;
854 return 1;
858 /* returns 1 on success */
859 int edit_new_cmd (WEdit * edit)
861 if (edit->modified) {
862 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
863 edit->force |= REDRAW_COMPLETELY;
864 return 0;
867 edit->force |= REDRAW_COMPLETELY;
869 return edit_renew (edit); /* if this gives an error, something has really screwed up */
872 /* returns 1 on error */
873 static int
874 edit_load_file_from_filename (WEdit * edit, char *exp)
876 int prev_locked = edit->locked;
877 char *prev_filename = g_strdup (edit->filename);
879 if (!edit_reload (edit, exp)) {
880 g_free (prev_filename);
881 return 1;
884 if (prev_locked)
885 edit_unlock_file (prev_filename);
886 g_free (prev_filename);
887 return 0;
890 static void
891 edit_load_syntax_file (WEdit * edit)
893 char *extdir;
894 int dir = 0;
896 if (geteuid () == 0) {
897 dir = query_dialog (_("Syntax file edit"),
898 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
899 _("&User"), _("&System Wide"));
902 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
903 if (!exist_file(extdir)) {
904 g_free (extdir);
905 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
908 if (dir == 0) {
909 char *buffer;
911 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
912 check_for_default (extdir, buffer);
913 edit_load_file_from_filename (edit, buffer);
914 g_free (buffer);
915 } else if (dir == 1)
916 edit_load_file_from_filename (edit, extdir);
918 g_free (extdir);
921 static void
922 edit_load_menu_file (WEdit * edit)
924 char *buffer;
925 char *menufile;
926 int dir = 0;
928 dir = query_dialog (
929 _(" Menu edit "),
930 _(" Which menu file do you want to edit? "), D_NORMAL,
931 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
934 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
936 if (!exist_file (menufile)) {
937 g_free (menufile);
938 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
941 switch (dir) {
942 case 0:
943 buffer = g_strdup (EDIT_LOCAL_MENU);
944 check_for_default (menufile, buffer);
945 chmod (buffer, 0600);
946 break;
948 case 1:
949 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
950 check_for_default (menufile, buffer);
951 break;
953 case 2:
954 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
955 if (!exist_file (buffer)) {
956 g_free (buffer);
957 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
959 break;
961 default:
962 g_free (menufile);
963 return;
966 edit_load_file_from_filename (edit, buffer);
968 g_free (buffer);
969 g_free (menufile);
973 edit_load_cmd (WEdit *edit, edit_current_file_t what)
975 char *exp;
977 if (edit->modified
978 && (edit_query_dialog2
979 (_("Warning"),
980 _(" Current text was modified without a file save. \n"
981 " Continue discards these changes. "),
982 _("C&ontinue"), _("&Cancel")) == 1)) {
983 edit->force |= REDRAW_COMPLETELY;
984 return 0;
987 switch (what) {
988 case EDIT_FILE_COMMON:
989 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
990 MC_HISTORY_EDIT_LOAD, edit->filename);
992 if (exp) {
993 if (*exp)
994 edit_load_file_from_filename (edit, exp);
995 g_free (exp);
997 break;
999 case EDIT_FILE_SYNTAX:
1000 edit_load_syntax_file (edit);
1001 break;
1003 case EDIT_FILE_MENU:
1004 edit_load_menu_file (edit);
1005 break;
1007 default:
1008 break;
1011 edit->force |= REDRAW_COMPLETELY;
1012 return 0;
1016 if mark2 is -1 then marking is from mark1 to the cursor.
1017 Otherwise its between the markers. This handles this.
1018 Returns 1 if no text is marked.
1020 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
1022 if (edit->mark1 != edit->mark2) {
1023 if (edit->mark2 >= 0) {
1024 *start_mark = min (edit->mark1, edit->mark2);
1025 *end_mark = max (edit->mark1, edit->mark2);
1026 } else {
1027 *start_mark = min (edit->mark1, edit->curs1);
1028 *end_mark = max (edit->mark1, edit->curs1);
1029 edit->column2 = edit->curs_col + edit->over_col;
1031 return 0;
1032 } else {
1033 *start_mark = *end_mark = 0;
1034 edit->column2 = edit->column1 = 0;
1035 return 1;
1039 #define space_width 1
1041 void
1042 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
1044 long cursor;
1045 int i, col;
1046 cursor = edit->curs1;
1047 col = edit_get_col (edit);
1048 for (i = 0; i < size; i++) {
1049 if (data[i] == '\n') { /* fill in and move to next line */
1050 int l;
1051 long p;
1052 if (edit_get_byte (edit, edit->curs1) != '\n') {
1053 l = width - (edit_get_col (edit) - col);
1054 while (l > 0) {
1055 edit_insert (edit, ' ');
1056 l -= space_width;
1059 for (p = edit->curs1;; p++) {
1060 if (p == edit->last_byte) {
1061 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1062 edit_insert_ahead (edit, '\n');
1063 p++;
1064 break;
1066 if (edit_get_byte (edit, p) == '\n') {
1067 p++;
1068 break;
1071 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1072 l = col - edit_get_col (edit);
1073 while (l >= space_width) {
1074 edit_insert (edit, ' ');
1075 l -= space_width;
1077 continue;
1079 edit_insert (edit, data[i]);
1081 edit_cursor_move (edit, cursor - edit->curs1);
1084 #define TEMP_BUF_LEN 1024
1087 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1089 long cursor;
1090 int i, col;
1091 int blocklen = -1, width;
1092 unsigned char *data;
1093 cursor = edit->curs1;
1094 col = edit_get_col (edit);
1095 data = g_malloc (TEMP_BUF_LEN);
1096 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1097 for (width = 0; width < blocklen; width++) {
1098 if (data[width] == '\n')
1099 break;
1101 for (i = 0; i < blocklen; i++) {
1102 if (data[i] == '\n') { /* fill in and move to next line */
1103 int l;
1104 long p;
1105 if (edit_get_byte (edit, edit->curs1) != '\n') {
1106 l = width - (edit_get_col (edit) - col);
1107 while (l > 0) {
1108 edit_insert (edit, ' ');
1109 l -= space_width;
1112 for (p = edit->curs1;; p++) {
1113 if (p == edit->last_byte) {
1114 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1115 edit_insert_ahead (edit, '\n');
1116 p++;
1117 break;
1119 if (edit_get_byte (edit, p) == '\n') {
1120 p++;
1121 break;
1124 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1125 l = col - edit_get_col (edit);
1126 while (l >= space_width) {
1127 edit_insert (edit, ' ');
1128 l -= space_width;
1130 continue;
1132 edit_insert (edit, data[i]);
1135 edit_cursor_move (edit, cursor - edit->curs1);
1136 g_free(data);
1137 edit->force |= REDRAW_PAGE;
1138 return blocklen;
1141 void
1142 edit_block_copy_cmd (WEdit *edit)
1144 long start_mark, end_mark, current = edit->curs1;
1145 int size;
1146 unsigned char *copy_buf;
1148 edit_update_curs_col (edit);
1149 if (eval_marks (edit, &start_mark, &end_mark))
1150 return;
1152 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1154 /* all that gets pushed are deletes hence little space is used on the stack */
1156 edit_push_markers (edit);
1158 if (column_highlighting) {
1159 edit_insert_column_of_text (edit, copy_buf, size,
1160 abs (edit->column2 - edit->column1));
1161 } else {
1162 while (size--)
1163 edit_insert_ahead (edit, copy_buf[size]);
1166 g_free (copy_buf);
1167 edit_scroll_screen_over_cursor (edit);
1169 if (column_highlighting) {
1170 edit_set_markers (edit, 0, 0, 0, 0);
1171 edit_push_action (edit, COLUMN_ON);
1172 column_highlighting = 0;
1173 } else if (start_mark < current && end_mark > current)
1174 edit_set_markers (edit, start_mark,
1175 end_mark + end_mark - start_mark, 0, 0);
1177 edit->force |= REDRAW_PAGE;
1181 void
1182 edit_block_move_cmd (WEdit *edit)
1184 long count;
1185 long current;
1186 unsigned char *copy_buf;
1187 long start_mark, end_mark;
1188 int deleted = 0;
1189 int x = 0;
1191 if (eval_marks (edit, &start_mark, &end_mark))
1192 return;
1193 if (column_highlighting) {
1194 edit_update_curs_col (edit);
1195 x = edit->curs_col;
1196 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1197 if ((x > edit->column1 && x < edit->column2)
1198 || (x > edit->column2 && x < edit->column1))
1199 return;
1200 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1201 return;
1203 if ((end_mark - start_mark) > option_max_undo / 2)
1204 if (edit_query_dialog2
1205 (_("Warning"),
1207 (" Block is large, you may not be able to undo this action. "),
1208 _("C&ontinue"), _("&Cancel")))
1209 return;
1211 edit_push_markers (edit);
1212 current = edit->curs1;
1213 if (column_highlighting) {
1214 int size, c1, c2, line;
1215 line = edit->curs_line;
1216 if (edit->mark2 < 0)
1217 edit_mark_cmd (edit, 0);
1218 c1 = min (edit->column1, edit->column2);
1219 c2 = max (edit->column1, edit->column2);
1220 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1221 if (x < c2) {
1222 edit_block_delete_cmd (edit);
1223 deleted = 1;
1225 edit_move_to_line (edit, line);
1226 edit_cursor_move (edit,
1227 edit_move_forward3 (edit,
1228 edit_bol (edit, edit->curs1),
1229 x, 0) - edit->curs1);
1230 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1231 if (!deleted) {
1232 line = edit->curs_line;
1233 edit_update_curs_col (edit);
1234 x = edit->curs_col;
1235 edit_block_delete_cmd (edit);
1236 edit_move_to_line (edit, line);
1237 edit_cursor_move (edit,
1238 edit_move_forward3 (edit,
1239 edit_bol (edit,
1240 edit->curs1),
1241 x, 0) - edit->curs1);
1243 edit_set_markers (edit, 0, 0, 0, 0);
1244 edit_push_action (edit, COLUMN_ON);
1245 column_highlighting = 0;
1246 } else {
1247 copy_buf = g_malloc (end_mark - start_mark);
1248 edit_cursor_move (edit, start_mark - edit->curs1);
1249 edit_scroll_screen_over_cursor (edit);
1250 count = start_mark;
1251 while (count < end_mark) {
1252 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1253 count++;
1255 edit_scroll_screen_over_cursor (edit);
1256 edit_cursor_move (edit,
1257 current - edit->curs1 -
1258 (((current - edit->curs1) >
1259 0) ? end_mark - start_mark : 0));
1260 edit_scroll_screen_over_cursor (edit);
1261 while (count-- > start_mark)
1262 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1263 edit_set_markers (edit, edit->curs1,
1264 edit->curs1 + end_mark - start_mark, 0, 0);
1266 edit_scroll_screen_over_cursor (edit);
1267 g_free (copy_buf);
1268 edit->force |= REDRAW_PAGE;
1271 static void
1272 edit_delete_column_of_text (WEdit * edit)
1274 long p, q, r, m1, m2;
1275 int b, c, d;
1276 int n;
1278 eval_marks (edit, &m1, &m2);
1279 n = edit_move_forward (edit, m1, 0, m2) + 1;
1280 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1281 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1283 b = max(min (c, d), min (edit->column1, edit->column2));
1284 c = max (c, d + edit->over_col);
1286 while (n--) {
1287 r = edit_bol (edit, edit->curs1);
1288 p = edit_move_forward3 (edit, r, b, 0);
1289 q = edit_move_forward3 (edit, r, c, 0);
1290 if (p < m1)
1291 p = m1;
1292 if (q > m2)
1293 q = m2;
1294 edit_cursor_move (edit, p - edit->curs1);
1295 while (q > p) { /* delete line between margins */
1296 if (edit_get_byte (edit, edit->curs1) != '\n')
1297 edit_delete (edit, 1);
1298 q--;
1300 if (n) /* move to next line except on the last delete */
1301 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1305 /* if success return 0 */
1306 static int
1307 edit_block_delete (WEdit *edit)
1309 long count;
1310 long start_mark, end_mark;
1311 if (eval_marks (edit, &start_mark, &end_mark))
1312 return 0;
1313 if (column_highlighting && edit->mark2 < 0)
1314 edit_mark_cmd (edit, 0);
1315 if ((end_mark - start_mark) > option_max_undo / 2) {
1316 /* Warning message with a query to continue or cancel the operation */
1317 if (edit_query_dialog2
1318 (_("Warning"),
1320 (" Block is large, you may not be able to undo this action. "),
1321 _("C&ontinue"), _("&Cancel"))) {
1322 return 1;
1325 edit_push_markers (edit);
1326 edit_cursor_move (edit, start_mark - edit->curs1);
1327 edit_scroll_screen_over_cursor (edit);
1328 count = start_mark;
1329 if (start_mark < end_mark) {
1330 if (column_highlighting) {
1331 if (edit->mark2 < 0)
1332 edit_mark_cmd (edit, 0);
1333 edit_delete_column_of_text (edit);
1334 } else {
1335 while (count < end_mark) {
1336 edit_delete (edit, 1);
1337 count++;
1341 edit_set_markers (edit, 0, 0, 0, 0);
1342 edit->force |= REDRAW_PAGE;
1343 return 0;
1346 /* returns 1 if canceelled by user */
1347 int edit_block_delete_cmd (WEdit * edit)
1349 long start_mark, end_mark;
1350 if (eval_marks (edit, &start_mark, &end_mark)) {
1351 edit_delete_line (edit);
1352 return 0;
1354 return edit_block_delete (edit);
1357 #define INPUT_INDEX 9
1359 static gboolean
1360 editcmd_find (WEdit *edit, gsize *len)
1362 off_t search_start = edit->search_start;
1363 off_t search_end;
1364 long start_mark = 0;
1365 long end_mark = edit->last_byte;
1366 int mark_res = 0;
1368 if (edit->only_in_selection) {
1369 mark_res = eval_marks(edit, &start_mark, &end_mark);
1370 if (mark_res != 0) {
1371 edit->search->error = MC_SEARCH_E_NOTFOUND;
1372 edit->search->error_str = g_strdup(_(" Search string not found "));
1373 return FALSE;
1375 if (edit->replace_backwards) {
1376 if (search_start > end_mark || search_start <= start_mark) {
1377 search_start = end_mark;
1379 } else {
1380 if (search_start < start_mark || search_start >= end_mark) {
1381 search_start = start_mark;
1384 } else {
1385 if (edit->replace_backwards)
1386 end_mark = max(1, edit->curs1) - 1;
1388 if (edit->replace_backwards) {
1389 search_end = end_mark;
1390 while ((int) search_start >= start_mark) {
1391 if (search_end > search_start + edit->search->original_len
1392 && mc_search_is_fixed_search_str(edit->search)) {
1393 search_end = search_start + edit->search->original_len;
1395 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1396 && edit->search->normal_offset == search_start ) {
1397 return TRUE;
1399 search_start--;
1401 edit->search->error_str = g_strdup(_(" Search string not found "));
1402 } else {
1403 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1405 return FALSE;
1409 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1410 (and the above) routines to work properly - paul */
1412 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1414 static char *
1415 edit_replace_cmd__conv_to_display(char *str)
1417 #ifdef HAVE_CHARSET
1418 GString *tmp;
1419 tmp = str_convert_to_display (str);
1421 if (tmp && tmp->len){
1422 g_free(str);
1423 str = tmp->str;
1425 g_string_free (tmp, FALSE);
1426 return str;
1427 #else
1428 return g_strdup(str);
1429 #endif
1432 static char *
1433 edit_replace_cmd__conv_to_input(char *str)
1435 #ifdef HAVE_CHARSET
1436 GString *tmp;
1437 tmp = str_convert_to_input (str);
1439 if (tmp && tmp->len){
1440 g_free(str);
1441 str = tmp->str;
1443 g_string_free (tmp, FALSE);
1444 return str;
1445 #else
1446 return g_strdup(str);
1447 #endif
1449 /* call with edit = 0 before shutdown to close memory leaks */
1450 void
1451 edit_replace_cmd (WEdit *edit, int again)
1453 /* 1 = search string, 2 = replace with */
1454 static char *saved1 = NULL; /* saved default[123] */
1455 static char *saved2 = NULL;
1456 char *input1 = NULL; /* user input from the dialog */
1457 char *input2 = NULL;
1458 int replace_yes;
1459 long times_replaced = 0, last_search;
1460 gboolean once_found = FALSE;
1462 if (!edit) {
1463 g_free (saved1), saved1 = NULL;
1464 g_free (saved2), saved2 = NULL;
1465 return;
1468 last_search = edit->last_byte;
1470 edit->force |= REDRAW_COMPLETELY;
1472 if (again && !saved1 && !saved2)
1473 again = 0;
1475 if (again) {
1476 input1 = g_strdup (saved1 ? saved1 : "");
1477 input2 = g_strdup (saved2 ? saved2 : "");
1478 } else {
1479 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1480 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1482 edit_push_action (edit, KEY_PRESS + edit->start_display);
1484 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1486 g_free (disp1);
1487 g_free (disp2);
1489 if (input1 == NULL || *input1 == '\0') {
1490 edit->force = REDRAW_COMPLETELY;
1491 goto cleanup;
1494 input1 = edit_replace_cmd__conv_to_input(input1);
1495 input2 = edit_replace_cmd__conv_to_input(input2);
1497 g_free (saved1), saved1 = g_strdup (input1);
1498 g_free (saved2), saved2 = g_strdup (input2);
1500 if (edit->search) {
1501 mc_search_free(edit->search);
1502 edit->search = NULL;
1506 if (!edit->search) {
1507 edit->search = mc_search_new(input1, -1);
1508 if (edit->search == NULL) {
1509 edit->search_start = edit->curs1;
1510 return;
1512 edit->search->search_type = edit->search_type;
1513 edit->search->is_all_charsets = edit->all_codepages;
1514 edit->search->is_case_sentitive = edit->replace_case;
1515 edit->search->whole_words = edit->whole_words;
1516 edit->search->search_fn = edit_search_cmd_callback;
1519 if (edit->found_len && edit->search_start == edit->found_start + 1
1520 && edit->replace_backwards)
1521 edit->search_start--;
1523 if (edit->found_len && edit->search_start == edit->found_start - 1
1524 && !edit->replace_backwards)
1525 edit->search_start++;
1527 do {
1528 gsize len = 0;
1529 long new_start;
1531 if (! editcmd_find(edit, &len)) {
1532 if (!(edit->search->error == MC_SEARCH_E_OK ||
1533 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1534 edit_error_dialog (_ ("Search"), edit->search->error_str);
1536 break;
1538 once_found = TRUE;
1539 new_start = edit->search->normal_offset;
1541 edit->search_start = new_start = edit->search->normal_offset;
1542 /*returns negative on not found or error in pattern */
1544 if (edit->search_start >= 0) {
1545 guint i;
1547 edit->found_start = edit->search_start;
1548 i = edit->found_len = len;
1550 edit_cursor_move (edit, edit->search_start - edit->curs1);
1551 edit_scroll_screen_over_cursor (edit);
1553 replace_yes = 1;
1555 if (edit->replace_mode == 0) {
1556 int l;
1557 l = edit->curs_row - edit->num_widget_lines / 3;
1558 if (l > 0)
1559 edit_scroll_downward (edit, l);
1560 if (l < 0)
1561 edit_scroll_upward (edit, -l);
1563 edit_scroll_screen_over_cursor (edit);
1564 edit->force |= REDRAW_PAGE;
1565 edit_render_keypress (edit);
1567 /*so that undo stops at each query */
1568 edit_push_key_press (edit);
1569 /* and prompt 2/3 down */
1570 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1571 case B_ENTER:
1572 replace_yes = 1;
1573 break;
1574 case B_SKIP_REPLACE:
1575 replace_yes = 0;
1576 break;
1577 case B_REPLACE_ALL:
1578 edit->replace_mode=1;
1579 break;
1580 case B_CANCEL:
1581 replace_yes = 0;
1582 edit->replace_mode = -1;
1583 break;
1586 if (replace_yes) { /* delete then insert new */
1587 GString *repl_str, *tmp_str;
1588 tmp_str = g_string_new(input2);
1590 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1591 g_string_free(tmp_str, TRUE);
1592 if (edit->search->error != MC_SEARCH_E_OK)
1594 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1595 break;
1598 while (i--)
1599 edit_delete (edit, 1);
1601 while (++i < repl_str->len)
1602 edit_insert (edit, repl_str->str[i]);
1604 g_string_free(repl_str, TRUE);
1605 edit->found_len = i;
1607 /* so that we don't find the same string again */
1608 if (edit->replace_backwards) {
1609 last_search = edit->search_start;
1610 edit->search_start--;
1611 } else {
1612 edit->search_start += i;
1613 last_search = edit->last_byte;
1615 edit_scroll_screen_over_cursor (edit);
1616 } else {
1617 const char *msg = _(" Replace ");
1618 /* try and find from right here for next search */
1619 edit->search_start = edit->curs1;
1620 edit_update_curs_col (edit);
1622 edit->force |= REDRAW_PAGE;
1623 edit_render_keypress (edit);
1624 if (times_replaced) {
1625 message (D_NORMAL, msg, _(" %ld replacements made. "),
1626 times_replaced);
1627 } else
1628 query_dialog (msg, _(" Search string not found "),
1629 D_NORMAL, 1, _("&OK"));
1630 edit->replace_mode = -1;
1632 } while (edit->replace_mode >= 0);
1634 edit->force = REDRAW_COMPLETELY;
1635 edit_scroll_screen_over_cursor (edit);
1636 cleanup:
1637 g_free (input1);
1638 g_free (input2);
1642 void edit_search_cmd (WEdit * edit, int again)
1644 char *search_string = NULL, *search_string_dup = NULL;
1646 gsize len = 0;
1648 if (!edit)
1649 return;
1651 if (edit->search != NULL) {
1652 search_string = g_strndup(edit->search->original, edit->search->original_len);
1653 search_string_dup = search_string;
1654 } else {
1655 GList *history;
1656 history = history_get (MC_HISTORY_SHARED_SEARCH);
1657 if (history != NULL && history->data != NULL) {
1658 search_string_dup = search_string = (char *) g_strdup(history->data);
1659 history = g_list_first (history);
1660 g_list_foreach (history, (GFunc) g_free, NULL);
1661 g_list_free (history);
1663 edit->search_start = edit->curs1;
1666 if (!again) {
1667 #ifdef HAVE_CHARSET
1668 GString *tmp;
1669 if (search_string && *search_string) {
1670 tmp = str_convert_to_display (search_string);
1672 g_free(search_string_dup);
1673 search_string_dup = NULL;
1675 if (tmp && tmp->len)
1676 search_string = search_string_dup = tmp->str;
1677 g_string_free (tmp, FALSE);
1679 #endif /* HAVE_CHARSET */
1680 editcmd_dialog_search_show (edit, &search_string);
1681 #ifdef HAVE_CHARSET
1682 if (search_string && *search_string) {
1683 tmp = str_convert_to_input (search_string);
1684 if (tmp && tmp->len)
1685 search_string = tmp->str;
1687 g_string_free (tmp, FALSE);
1689 if (search_string_dup)
1690 g_free(search_string_dup);
1692 #endif /* HAVE_CHARSET */
1694 edit_push_action (edit, KEY_PRESS + edit->start_display);
1696 if (!search_string) {
1697 edit->force |= REDRAW_COMPLETELY;
1698 edit_scroll_screen_over_cursor (edit);
1699 return;
1702 if (edit->search) {
1703 mc_search_free(edit->search);
1704 edit->search = NULL;
1708 if (!edit->search) {
1709 edit->search = mc_search_new(search_string, -1);
1710 if (edit->search == NULL) {
1711 edit->search_start = edit->curs1;
1712 return;
1714 edit->search->search_type = edit->search_type;
1715 edit->search->is_all_charsets = edit->all_codepages;
1716 edit->search->is_case_sentitive = edit->replace_case;
1717 edit->search->whole_words = edit->whole_words;
1718 edit->search->search_fn = edit_search_cmd_callback;
1721 if (search_create_bookmark) {
1722 edit_search_cmd_search_create_bookmark(edit);
1723 } else {
1724 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1725 edit->search_start--;
1727 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1728 edit->search_start++;
1731 if (editcmd_find(edit, &len)) {
1732 edit->found_start = edit->search_start = edit->search->normal_offset;
1733 edit->found_len = len;
1734 edit->over_col = 0;
1735 edit_cursor_move (edit, edit->search_start - edit->curs1);
1736 edit_scroll_screen_over_cursor (edit);
1737 if (edit->replace_backwards)
1738 edit->search_start--;
1739 else
1740 edit->search_start++;
1741 } else {
1742 edit->search_start = edit->curs1;
1743 if (edit->search->error_str)
1744 edit_error_dialog (_ ("Search"), edit->search->error_str);
1748 edit->force |= REDRAW_COMPLETELY;
1749 edit_scroll_screen_over_cursor (edit);
1754 * Check if it's OK to close the editor. If there are unsaved changes,
1755 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1758 edit_ok_to_exit (WEdit *edit)
1760 if (!edit->modified)
1761 return 1;
1763 switch (edit_query_dialog3
1764 (_("Quit"), _(" File was modified, Save with exit? "),
1765 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1766 case 1:
1767 edit_push_markers (edit);
1768 edit_set_markers (edit, 0, 0, 0, 0);
1769 if (!edit_save_cmd (edit))
1770 return 0;
1771 break;
1772 case 2:
1773 break;
1774 case 0:
1775 case -1:
1776 return 0;
1779 return 1;
1782 /* Return a null terminated length of text. Result must be g_free'd */
1783 static unsigned char *
1784 edit_get_block (WEdit *edit, long start, long finish, int *l)
1786 unsigned char *s, *r;
1787 r = s = g_malloc (finish - start + 1);
1788 if (column_highlighting) {
1789 *l = 0;
1790 /* copy from buffer, excluding chars that are out of the column 'margins' */
1791 while (start < finish) {
1792 int c, x;
1793 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1794 start);
1795 c = edit_get_byte (edit, start);
1796 if ((x >= edit->column1 && x < edit->column2)
1797 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1798 *s++ = c;
1799 (*l)++;
1801 start++;
1803 } else {
1804 *l = finish - start;
1805 while (start < finish)
1806 *s++ = edit_get_byte (edit, start++);
1808 *s = 0;
1809 return r;
1812 /* save block, returns 1 on success */
1814 edit_save_block (WEdit * edit, const char *filename, long start,
1815 long finish)
1817 int len, file;
1819 if ((file =
1820 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1821 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1822 return 0;
1824 if (column_highlighting) {
1825 int r;
1826 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1827 if (r > 0) {
1828 unsigned char *block, *p;
1829 p = block = edit_get_block (edit, start, finish, &len);
1830 while (len) {
1831 r = mc_write (file, p, len);
1832 if (r < 0)
1833 break;
1834 p += r;
1835 len -= r;
1837 g_free (block);
1839 } else {
1840 unsigned char *buf;
1841 int i = start, end;
1842 len = finish - start;
1843 buf = g_malloc (TEMP_BUF_LEN);
1844 while (start != finish) {
1845 end = min (finish, start + TEMP_BUF_LEN);
1846 for (; i < end; i++)
1847 buf[i - start] = edit_get_byte (edit, i);
1848 len -= mc_write (file, (char *) buf, end - start);
1849 start = end;
1851 g_free (buf);
1853 mc_close (file);
1854 if (len)
1855 return 0;
1856 return 1;
1859 /* copies a block to clipboard file */
1860 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1862 int ret;
1863 gchar *tmp;
1864 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1865 ret = edit_save_block (edit, tmp, start, finish);
1866 g_free(tmp);
1867 return ret;
1871 void edit_paste_from_history (WEdit *edit)
1873 (void) edit;
1874 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1877 int edit_copy_to_X_buf_cmd (WEdit * edit)
1879 long start_mark, end_mark;
1880 if (eval_marks (edit, &start_mark, &end_mark))
1881 return 0;
1882 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1883 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1884 return 1;
1886 edit_mark_cmd (edit, 1);
1887 return 0;
1890 int edit_cut_to_X_buf_cmd (WEdit * edit)
1892 long start_mark, end_mark;
1893 if (eval_marks (edit, &start_mark, &end_mark))
1894 return 0;
1895 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1896 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1897 return 1;
1899 edit_block_delete_cmd (edit);
1900 edit_mark_cmd (edit, 1);
1901 return 0;
1904 void edit_paste_from_X_buf_cmd (WEdit * edit)
1906 gchar *tmp;
1907 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1908 edit_insert_file (edit, tmp);
1909 g_free(tmp);
1914 * Ask user for the line and go to that line.
1915 * Negative numbers mean line from the end (i.e. -1 is the last line).
1917 void
1918 edit_goto_cmd (WEdit *edit)
1920 char *f;
1921 static long line = 0; /* line as typed, saved as default */
1922 long l;
1923 char *error;
1924 char s[32];
1926 g_snprintf (s, sizeof (s), "%ld", line);
1927 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1928 line ? s : "");
1929 if (!f)
1930 return;
1932 if (!*f) {
1933 g_free (f);
1934 return;
1937 l = strtol (f, &error, 0);
1938 if (*error) {
1939 g_free (f);
1940 return;
1943 line = l;
1944 if (l < 0)
1945 l = edit->total_lines + l + 2;
1946 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
1947 edit_move_to_line (edit, l - 1);
1948 edit->force |= REDRAW_COMPLETELY;
1949 g_free (f);
1953 /* Return 1 on success */
1955 edit_save_block_cmd (WEdit *edit)
1957 long start_mark, end_mark;
1958 char *exp, *tmp;
1960 if (eval_marks (edit, &start_mark, &end_mark))
1961 return 1;
1963 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1964 exp =
1965 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
1966 MC_HISTORY_EDIT_SAVE_BLOCK,
1967 tmp);
1968 g_free(tmp);
1969 edit_push_action (edit, KEY_PRESS + edit->start_display);
1970 if (exp) {
1971 if (!*exp) {
1972 g_free (exp);
1973 return 0;
1974 } else {
1975 if (edit_save_block (edit, exp, start_mark, end_mark)) {
1976 g_free (exp);
1977 edit->force |= REDRAW_COMPLETELY;
1978 return 1;
1979 } else {
1980 g_free (exp);
1981 edit_error_dialog (_(" Save Block "),
1982 get_sys_error (_
1983 (" Cannot save file. ")));
1987 edit->force |= REDRAW_COMPLETELY;
1988 return 0;
1992 /* returns 1 on success */
1994 edit_insert_file_cmd (WEdit *edit)
1996 gchar *tmp;
1997 char *exp;
1999 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
2000 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
2001 MC_HISTORY_EDIT_INSERT_FILE,
2002 tmp);
2003 g_free(tmp);
2004 edit_push_action (edit, KEY_PRESS + edit->start_display);
2005 if (exp) {
2006 if (!*exp) {
2007 g_free (exp);
2008 return 0;
2009 } else {
2010 if (edit_insert_file (edit, exp)) {
2011 g_free (exp);
2012 edit->force |= REDRAW_COMPLETELY;
2013 return 1;
2014 } else {
2015 g_free (exp);
2016 edit_error_dialog (_(" Insert File "),
2017 get_sys_error (_
2018 (" Cannot insert file. ")));
2022 edit->force |= REDRAW_COMPLETELY;
2023 return 0;
2026 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2027 int edit_sort_cmd (WEdit * edit)
2029 static char *old = 0;
2030 char *exp, *tmp;
2031 long start_mark, end_mark;
2032 int e;
2034 if (eval_marks (edit, &start_mark, &end_mark)) {
2035 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2036 return 0;
2039 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
2040 edit_save_block (edit, tmp, start_mark, end_mark);
2041 g_free(tmp);
2043 exp = input_dialog (_(" Run Sort "),
2044 _(" Enter sort options (see manpage) separated by whitespace: "),
2045 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
2047 if (!exp)
2048 return 1;
2049 g_free (old);
2050 old = exp;
2051 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
2052 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2053 e = system (tmp);
2054 g_free(tmp);
2055 if (e) {
2056 if (e == -1 || e == 127) {
2057 edit_error_dialog (_(" Sort "),
2058 get_sys_error (_(" Cannot execute sort command ")));
2059 } else {
2060 char q[8];
2061 sprintf (q, "%d ", e);
2062 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
2063 edit_error_dialog (_(" Sort "), tmp);
2064 g_free(tmp);
2066 return -1;
2069 edit->force |= REDRAW_COMPLETELY;
2071 if (edit_block_delete_cmd (edit))
2072 return 1;
2073 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2074 edit_insert_file (edit, tmp);
2075 g_free(tmp);
2076 return 0;
2080 * Ask user for a command, execute it and paste its output back to the
2081 * editor.
2084 edit_ext_cmd (WEdit *edit)
2086 char *exp, *tmp;
2087 int e;
2089 exp =
2090 input_dialog (_("Paste output of external command"),
2091 _("Enter shell command(s):"),
2092 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2094 if (!exp)
2095 return 1;
2097 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2098 e = system (tmp);
2099 g_free(tmp);
2100 g_free (exp);
2102 if (e) {
2103 edit_error_dialog (_("External command"),
2104 get_sys_error (_("Cannot execute command")));
2105 return -1;
2108 edit->force |= REDRAW_COMPLETELY;
2109 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2110 edit_insert_file (edit, tmp);
2111 g_free(tmp);
2112 return 0;
2115 /* if block is 1, a block must be highlighted and the shell command
2116 processes it. If block is 0 the shell command is a straight system
2117 command, that just produces some output which is to be inserted */
2118 void
2119 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2121 long start_mark, end_mark;
2122 char buf[BUFSIZ];
2123 FILE *script_home = NULL;
2124 FILE *script_src = NULL;
2125 FILE *block_file = NULL;
2126 gchar *o, *h, *b, *tmp;
2127 char *quoted_name = NULL;
2129 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2130 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2131 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2133 if (!(script_home = fopen (h, "r"))) {
2134 if (!(script_home = fopen (h, "w"))) {
2135 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2136 edit_error_dialog ("", get_sys_error (tmp));
2137 g_free(tmp);
2138 goto edit_block_process_cmd__EXIT;
2140 if (!(script_src = fopen (o, "r"))) {
2141 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2142 if (!(script_src = fopen (o, "r"))) {
2143 fclose (script_home);
2144 unlink (h);
2145 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2146 edit_error_dialog ("", get_sys_error (tmp));
2147 g_free(tmp);
2148 goto edit_block_process_cmd__EXIT;
2151 while (fgets (buf, sizeof (buf), script_src))
2152 fputs (buf, script_home);
2153 if (fclose (script_home)) {
2154 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2155 edit_error_dialog ("", get_sys_error (tmp));
2156 g_free(tmp);
2157 goto edit_block_process_cmd__EXIT;
2159 chmod (h, 0700);
2160 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2161 edit_error_dialog ("", get_sys_error (tmp));
2162 g_free(tmp);
2165 open_error_pipe ();
2167 if (block) { /* for marked block run indent formatter */
2168 if (eval_marks (edit, &start_mark, &end_mark)) {
2169 edit_error_dialog (_("Process block"),
2171 (" You must first highlight a block of text. "));
2172 goto edit_block_process_cmd__EXIT;
2174 edit_save_block (edit, b, start_mark, end_mark);
2175 quoted_name = name_quote (edit->filename, 0);
2177 * Run script.
2178 * Initial space is to avoid polluting bash history.
2179 * Arguments:
2180 * $1 - name of the edited file (to check its extension etc).
2181 * $2 - file containing the current block.
2182 * $3 - file where error messages should be put
2183 * (for compatibility with old scripts).
2185 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2186 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2187 system (tmp);
2188 g_free(tmp);
2189 } else {
2191 * No block selected, just execute the command for the file.
2192 * Arguments:
2193 * $1 - name of the edited file.
2195 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2196 quoted_name, (char *) NULL);
2197 system (tmp);
2198 g_free(tmp);
2200 g_free (quoted_name);
2201 close_error_pipe (D_NORMAL, NULL);
2203 edit_refresh_cmd (edit);
2204 edit->force |= REDRAW_COMPLETELY;
2206 /* insert result block */
2207 if (block) {
2208 if (edit_block_delete_cmd (edit))
2209 goto edit_block_process_cmd__EXIT;
2210 edit_insert_file (edit, b);
2211 if ((block_file = fopen (b, "w")))
2212 fclose (block_file);
2213 goto edit_block_process_cmd__EXIT;
2215 edit_block_process_cmd__EXIT:
2216 g_free(b);
2217 g_free(h);
2218 g_free(o);
2219 return;
2222 /* prints at the cursor */
2223 /* returns the number of chars printed */
2224 int edit_print_string (WEdit * e, const char *s)
2226 int i = 0;
2227 while (s[i])
2228 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2229 e->force |= REDRAW_COMPLETELY;
2230 edit_update_screen (e);
2231 return i;
2235 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2237 FILE *p = 0;
2238 char *s;
2240 to = name_quote (to, 0);
2241 subject = name_quote (subject, 0);
2242 cc = name_quote (cc, 0);
2243 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2244 g_free (to);
2245 g_free (subject);
2246 g_free (cc);
2248 if (s) {
2249 p = popen (s, "w");
2250 g_free (s);
2253 if (p) {
2254 long i;
2255 for (i = 0; i < edit->last_byte; i++)
2256 fputc (edit_get_byte (edit, i), p);
2257 pclose (p);
2261 #define MAIL_DLG_HEIGHT 12
2263 void edit_mail_dialog (WEdit * edit)
2265 char *tmail_to;
2266 char *tmail_subject;
2267 char *tmail_cc;
2269 static char *mail_cc_last = 0;
2270 static char *mail_subject_last = 0;
2271 static char *mail_to_last = 0;
2273 QuickDialog Quick_input =
2274 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2275 "[Input Line Keys]", 0, 0};
2277 QuickWidget quick_widgets[] =
2279 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2280 0, NULL, NULL, NULL},
2281 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
2282 0, NULL, NULL, NULL},
2283 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2284 0, "mail-dlg-input", NULL, NULL},
2285 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2286 0, 0, NULL, NULL},
2287 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2288 0, "mail-dlg-input-2", NULL, NULL},
2289 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2290 0, 0, NULL, NULL},
2291 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2292 0, "mail-dlg-input-3", NULL, NULL},
2293 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2294 0, 0, NULL, NULL},
2295 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2296 0, 0, NULL, NULL},
2297 NULL_QuickWidget};
2299 quick_widgets[2].str_result = &tmail_cc;
2300 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2301 quick_widgets[4].str_result = &tmail_subject;
2302 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2303 quick_widgets[6].str_result = &tmail_to;
2304 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2306 Quick_input.widgets = quick_widgets;
2308 if (quick_dialog (&Quick_input) != B_CANCEL) {
2309 g_free (mail_cc_last);
2310 g_free (mail_subject_last);
2311 g_free (mail_to_last);
2312 mail_cc_last = tmail_cc;
2313 mail_subject_last = tmail_subject;
2314 mail_to_last = tmail_to;
2315 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2320 /*******************/
2321 /* Word Completion */
2322 /*******************/
2324 static gboolean is_break_char(char c)
2326 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2329 /* find first character of current word */
2330 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2332 int i, c, last;
2334 /* return if at begin of file */
2335 if (edit->curs1 <= 0)
2336 return 0;
2338 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2339 /* return if not at end or in word */
2340 if (is_break_char(c))
2341 return 0;
2343 /* search start of word to be completed */
2344 for (i = 2;; i++) {
2345 /* return if at begin of file */
2346 if (edit->curs1 - i < 0)
2347 return 0;
2349 last = c;
2350 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2352 if (is_break_char(c)) {
2353 /* return if word starts with digit */
2354 if (isdigit (last))
2355 return 0;
2357 *word_start = edit->curs1 - (i - 1); /* start found */
2358 *word_len = i - 1;
2359 break;
2362 /* success */
2363 return 1;
2366 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2368 /* collect the possible completions */
2369 static int
2370 edit_collect_completions (WEdit *edit, long start, int word_len,
2371 char *match_expr, struct selection *compl,
2372 int *num)
2374 gsize len = 0;
2375 gsize max_len = 0;
2376 gsize i;
2377 int skip;
2378 GString *temp;
2379 mc_search_t *srch;
2381 srch = mc_search_new(match_expr, -1);
2382 if (srch == NULL)
2383 return 0;
2385 srch->search_type = MC_SEARCH_T_REGEX;
2386 srch->is_case_sentitive = TRUE;
2387 srch->search_fn = edit_search_cmd_callback;
2389 /* collect max MAX_WORD_COMPLETIONS completions */
2390 start--;
2391 while (*num < MAX_WORD_COMPLETIONS) {
2392 /* get next match */
2393 if (mc_search_run (srch, (void *) edit, start+1, edit->last_byte, &len) == FALSE)
2394 break;
2395 start = srch->normal_offset;
2397 /* add matched completion if not yet added */
2398 temp = g_string_new("");
2399 for (i = 0; i < len; i++){
2400 skip = edit_get_byte(edit, start+i);
2401 if (isspace(skip))
2402 continue;
2403 g_string_append_c (temp, skip);
2406 skip = 0;
2408 for (i = 0; i < (gsize) *num; i++) {
2409 if (strncmp
2411 (char *) &compl[i].text[word_len],
2412 (char *) &temp->str[word_len],
2413 max (len, compl[i].len) - (gsize)word_len
2414 ) == 0) {
2415 skip = 1;
2416 break; /* skip it, already added */
2419 if (skip) {
2420 g_string_free(temp, TRUE);
2421 continue;
2424 compl[*num].text = temp->str;
2425 compl[*num].len = temp->len;
2426 (*num)++;
2427 g_string_free(temp, FALSE);
2429 /* note the maximal length needed for the completion dialog */
2430 if (len > max_len)
2431 max_len = len;
2433 mc_search_free(srch);
2434 return max_len;
2438 * Complete current word using regular expression search
2439 * backwards beginning at the current cursor position.
2441 void
2442 edit_complete_word_cmd (WEdit *edit)
2444 int word_len = 0, num_compl = 0;
2445 gsize i, max_len;
2446 long word_start = 0;
2447 unsigned char *bufpos;
2448 char *match_expr;
2449 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2451 /* search start of word to be completed */
2452 if (!edit_find_word_start (edit, &word_start, &word_len))
2453 return;
2455 /* prepare match expression */
2456 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2457 [word_start & M_EDIT_BUF_SIZE];
2459 match_expr = g_strdup_printf ("(^|\\s)%.*s[^\\s\\.=\\+\\{\\}\\[\\]\\(\\)\\\\\\!\\,<>\\?\\/@#\\$%%\\^&\\*\\~\\|\\\"'\\:\\;]+", word_len, bufpos);
2461 /* collect the possible completions */
2462 /* start search from begin to end of file */
2463 max_len =
2464 edit_collect_completions (edit, 0, word_len, match_expr,
2465 (struct selection *) &compl, &num_compl);
2467 if (num_compl > 0) {
2468 /* insert completed word if there is only one match */
2469 if (num_compl == 1) {
2470 for (i = word_len; i < compl[0].len; i++)
2471 edit_insert (edit, *(compl[0].text + i));
2473 /* more than one possible completion => ask the user */
2474 else {
2475 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2476 /* !!! pressed again the selection dialog pops up, but that !!! */
2477 /* !!! seems to require a further internal state !!! */
2478 /*tty_beep (); */
2480 /* let the user select the preferred completion */
2481 editcmd_dialog_completion_show (edit, max_len, word_len,
2482 (struct selection *) &compl,
2483 num_compl);
2487 g_free (match_expr);
2488 /* release memory before return */
2489 for (i = 0; i < (gsize) num_compl; i++)
2490 g_free (compl[i].text);
2494 void
2495 edit_select_codepage_cmd (WEdit *edit)
2497 #ifdef HAVE_CHARSET
2498 const char *cp_id = NULL;
2499 if (do_select_codepage ()) {
2500 cp_id = get_codepage_id (source_codepage >= 0 ?
2501 source_codepage : display_codepage);
2503 if (cp_id != NULL) {
2504 GIConv conv;
2505 conv = str_crt_conv_from (cp_id);
2506 if (conv != INVALID_CONV) {
2507 if (edit->converter != str_cnv_from_term)
2508 str_close_conv (edit->converter);
2509 edit->converter = conv;
2514 if (cp_id != NULL)
2515 edit->utf8 = str_isutf8 (cp_id);
2518 edit->force = REDRAW_COMPLETELY;
2519 edit_refresh_cmd (edit);
2520 #endif
2523 void
2524 edit_insert_literal_cmd (WEdit *edit)
2526 int char_for_insertion =
2527 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2528 _(" Press any key: "), 0);
2529 edit_execute_key_command (edit, -1,
2530 ascii_alpha_to_cntrl (char_for_insertion));
2533 void
2534 edit_execute_macro_cmd (WEdit *edit)
2536 int command =
2537 CK_Macro (editcmd_dialog_raw_key_query
2538 (_(" Execute Macro "), _(" Press macro hotkey: "),
2539 1));
2540 if (command == CK_Macro (0))
2541 command = CK_Insert_Char;
2543 edit_execute_key_command (edit, command, -1);
2546 void
2547 edit_begin_end_macro_cmd(WEdit *edit)
2549 int command;
2551 /* edit is a pointer to the widget */
2552 if (edit) {
2553 command =
2554 edit->macro_i <
2555 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2556 edit_execute_key_command (edit, command, -1);
2561 edit_load_forward_cmd (WEdit *edit)
2563 if (edit->modified) {
2564 if (edit_query_dialog2
2565 (_("Warning"),
2566 _(" Current text was modified without a file save. \n"
2567 " Continue discards these changes. "), _("C&ontinue"),
2568 _("&Cancel"))) {
2569 edit->force |= REDRAW_COMPLETELY;
2570 return 0;
2573 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2574 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2575 return 1;
2577 edit_stack_iterator++;
2578 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2579 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2580 edit_history_moveto[edit_stack_iterator].line);
2581 return 0;
2582 } else {
2583 return 1;
2585 } else {
2586 return 1;
2591 edit_load_back_cmd (WEdit *edit)
2593 if (edit->modified) {
2594 if (edit_query_dialog2
2595 (_("Warning"),
2596 _(" Current text was modified without a file save. \n"
2597 " Continue discards these changes. "), _("C&ontinue"),
2598 _("&Cancel"))) {
2599 edit->force |= REDRAW_COMPLETELY;
2600 return 0;
2603 if ( edit_stack_iterator > 0 ) {
2604 edit_stack_iterator--;
2605 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2606 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2607 edit_history_moveto[edit_stack_iterator].line);
2608 return 0;
2609 } else {
2610 return 1;
2612 } else {
2613 return 1;
2617 void
2618 edit_get_match_keyword_cmd (WEdit *edit)
2620 int word_len = 0;
2621 int num_def = 0;
2622 int max_len = 0;
2623 int i;
2624 long word_start = 0;
2625 unsigned char *bufpos;
2626 char *match_expr;
2627 char *path = NULL;
2628 char *ptr = NULL;
2629 char *tagfile = NULL;
2631 etags_hash_t def_hash[MAX_DEFINITIONS];
2633 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2634 def_hash[i].filename = NULL;
2637 /* search start of word to be completed */
2638 if (!edit_find_word_start (edit, &word_start, &word_len))
2639 return;
2641 /* prepare match expression */
2642 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2643 [word_start & M_EDIT_BUF_SIZE];
2644 match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
2646 ptr = g_get_current_dir ();
2647 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2648 g_free (ptr);
2650 /* Recursive search file 'TAGS' in parent dirs */
2651 do {
2652 ptr = g_path_get_dirname (path);
2653 g_free(path); path = ptr;
2654 g_free (tagfile);
2655 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2656 if ( exist_file (tagfile) )
2657 break;
2658 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2660 if (tagfile){
2661 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2662 g_free (tagfile);
2664 g_free (path);
2666 max_len = MAX_WIDTH_DEF_DIALOG;
2667 word_len = 0;
2668 if ( num_def > 0 ) {
2669 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2670 (etags_hash_t *) &def_hash,
2671 num_def);
2673 g_free (match_expr);
2676 void
2677 edit_move_block_to_right (WEdit * edit)
2679 long start_mark, end_mark;
2680 long cur_bol, start_bol;
2682 if ( eval_marks (edit, &start_mark, &end_mark) )
2683 return;
2685 start_bol = edit_bol (edit, start_mark);
2686 cur_bol = edit_bol (edit, end_mark - 1);
2687 do {
2688 edit_cursor_move (edit, cur_bol - edit->curs1);
2689 if ( option_fill_tabs_with_spaces ) {
2690 if ( option_fake_half_tabs ) {
2691 insert_spaces_tab (edit, 1);
2692 } else {
2693 insert_spaces_tab (edit, 0);
2695 } else {
2696 edit_insert (edit, '\t');
2698 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2699 if ( cur_bol == 0 ) {
2700 break;
2702 cur_bol = edit_bol (edit, cur_bol - 1);
2703 } while (cur_bol >= start_bol) ;
2704 edit->force |= REDRAW_PAGE;
2707 void
2708 edit_move_block_to_left (WEdit * edit)
2710 long start_mark, end_mark;
2711 long cur_bol, start_bol;
2712 int i, del_tab_width;
2713 int next_char;
2715 if ( eval_marks (edit, &start_mark, &end_mark) )
2716 return;
2718 start_bol = edit_bol (edit, start_mark);
2719 cur_bol = edit_bol (edit, end_mark - 1);
2720 do {
2721 edit_cursor_move (edit, cur_bol - edit->curs1);
2722 if (option_fake_half_tabs) {
2723 del_tab_width = HALF_TAB_SIZE;
2724 } else {
2725 del_tab_width = option_tab_spacing;
2727 next_char = edit_get_byte (edit, edit->curs1);
2728 if ( next_char == '\t' ) {
2729 edit_delete (edit, 1);
2730 } else if ( next_char == ' ' ) {
2731 for (i = 1; i <= del_tab_width; i++) {
2732 if ( next_char == ' ' ) {
2733 edit_delete (edit, 1);
2735 next_char = edit_get_byte (edit, edit->curs1);
2738 if ( cur_bol == 0 ) {
2739 break;
2741 cur_bol = edit_bol (edit, cur_bol - 1);
2742 } while (cur_bol >= start_bol) ;
2743 edit->force |= REDRAW_PAGE;