Hide private API of editor (#361).
[midnight-commander.git] / edit / editcmd.c
blob54bcbcaf9ee0bea47b075df59cd301d9f27963dd
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>
47 #include "../src/global.h"
48 #include "../src/history.h"
50 #include "edit-impl.h"
51 #include "editlock.h"
52 #include "editcmddef.h"
53 #include "edit-widget.h"
54 #include "editcmd_dialogs.h"
55 #include "../edit/etags.h"
56 #include "../src/panel.h"
58 #include "../src/tty.h" /* LINES */
59 #include "../src/widget.h" /* listbox_new() */
60 #include "../src/layout.h" /* clr_scr() */
61 #include "../src/main.h" /* mc_home source_codepage */
62 #include "../src/help.h" /* interactive_display() */
63 #include "../src/key.h" /* XCTRL */
64 #include "../src/wtools.h" /* message() */
65 #include "../src/charsets.h"
66 #include "../src/selcodepage.h"
67 #include "../src/strutil.h" /* utf string functions */
69 /* globals: */
71 /* search and replace: */
72 static int search_create_bookmark = 0;
73 /* static int search_in_all_charsets = 0; */
75 /* queries on a save */
76 int edit_confirm_save = 1;
78 static int edit_save_cmd (WEdit *edit);
79 static unsigned char *edit_get_block (WEdit *edit, long start,
80 long finish, int *l);
82 static void
83 edit_search_cmd_search_create_bookmark(WEdit * edit)
85 int found = 0, books = 0;
86 int l = 0, l_last = -1;
87 long q = 0;
88 gsize len = 0;
90 for (;;) {
91 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
92 break;
94 found++;
95 l += edit_count_lines (edit, q, edit->search->normal_offset);
96 if (l != l_last) {
97 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
98 books++;
100 l_last = l;
101 q = edit->search->normal_offset + 1;
104 if (found) {
105 /* in response to number of bookmarks added because of string being found %d times */
106 message (D_NORMAL, _("Search"), _(" %d items found, %d bookmarks added "), found, books);
107 } else {
108 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
112 static int
113 edit_search_cmd_callback(const void *user_data, gsize char_offset)
115 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
118 void edit_help_cmd (WEdit * edit)
120 interactive_display (NULL, "[Internal File Editor]");
121 edit->force |= REDRAW_COMPLETELY;
124 void edit_refresh_cmd (WEdit * edit)
126 #ifndef HAVE_SLANG
127 clr_scr();
128 do_refresh();
129 #else
131 int color;
132 edit_get_syntax_color (edit, -1, &color);
134 touchwin(stdscr);
135 #endif /* !HAVE_SLANG */
136 mc_refresh();
137 doupdate();
140 /* If 0 (quick save) then a) create/truncate <filename> file,
141 b) save to <filename>;
142 if 1 (safe save) then a) save to <tempnam>,
143 b) rename <tempnam> to <filename>;
144 if 2 (do backups) then a) save to <tempnam>,
145 b) rename <filename> to <filename.backup_ext>,
146 c) rename <tempnam> to <filename>. */
148 /* returns 0 on error, -1 on abort */
149 static int
150 edit_save_file (WEdit *edit, const char *filename)
152 char *p;
153 gchar *tmp;
154 long filelen = 0;
155 char *savename = 0;
156 gchar *real_filename;
157 int this_save_mode, fd = -1;
159 if (!filename)
160 return 0;
161 if (!*filename)
162 return 0;
164 if (*filename != PATH_SEP && edit->dir) {
165 real_filename = concat_dir_and_file (edit->dir, filename);
166 } else {
167 real_filename = g_strdup(filename);
170 this_save_mode = option_save_mode;
171 if (this_save_mode != EDIT_QUICK_SAVE) {
172 if (!vfs_file_is_local (real_filename) ||
173 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
175 * The file does not exists yet, so no safe save or
176 * backup are necessary.
178 this_save_mode = EDIT_QUICK_SAVE;
180 if (fd != -1)
181 mc_close (fd);
184 if (this_save_mode == EDIT_QUICK_SAVE &&
185 !edit->skip_detach_prompt) {
186 int rv;
187 struct stat sb;
189 rv = mc_stat (real_filename, &sb);
190 if (rv == 0 && sb.st_nlink > 1) {
191 rv = edit_query_dialog3 (_("Warning"),
192 _(" File has hard-links. Detach before saving? "),
193 _("&Yes"), _("&No"), _("&Cancel"));
194 switch (rv) {
195 case 0:
196 this_save_mode = EDIT_SAFE_SAVE;
197 /* fallthrough */
198 case 1:
199 edit->skip_detach_prompt = 1;
200 break;
201 default:
202 g_free(real_filename);
203 return -1;
207 /* Prevent overwriting changes from other editor sessions. */
208 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
210 /* The default action is "Cancel". */
211 query_set_sel(1);
213 rv = edit_query_dialog2 (
214 _("Warning"),
215 _("The file has been modified in the meantime. Save anyway?"),
216 _("&Yes"),
217 _("&Cancel"));
218 if (rv != 0){
219 g_free(real_filename);
220 return -1;
225 if (this_save_mode != EDIT_QUICK_SAVE) {
226 char *savedir, *saveprefix;
227 const char *slashpos;
228 slashpos = strrchr (real_filename, PATH_SEP);
229 if (slashpos) {
230 savedir = g_strdup (real_filename);
231 savedir[slashpos - real_filename + 1] = '\0';
232 } else
233 savedir = g_strdup (".");
234 saveprefix = concat_dir_and_file (savedir, "cooledit");
235 g_free (savedir);
236 fd = mc_mkstemps (&savename, saveprefix, NULL);
237 g_free (saveprefix);
238 if (!savename){
239 g_free(real_filename);
240 return 0;
242 /* FIXME:
243 * Close for now because mc_mkstemps use pure open system call
244 * to create temporary file and it needs to be reopened by
245 * VFS-aware mc_open().
247 close (fd);
248 } else
249 savename = g_strdup (real_filename);
251 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
252 mc_chmod (savename, edit->stat1.st_mode);
254 if ((fd =
255 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
256 edit->stat1.st_mode)) == -1)
257 goto error_save;
259 /* pipe save */
260 if ((p = edit_get_write_filter (savename, real_filename))) {
261 FILE *file;
263 mc_close (fd);
264 file = (FILE *) popen (p, "w");
266 if (file) {
267 filelen = edit_write_stream (edit, file);
268 #if 1
269 pclose (file);
270 #else
271 if (pclose (file) != 0) {
272 tmp = g_strconcat (_(" Error writing to pipe: "),
273 p, " ", (char *) NULL);
274 edit_error_dialog (_("Error"), tmp);
275 g_free(tmp);
276 g_free (p);
277 goto error_save;
279 #endif
280 } else {
281 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
282 p, " ", (char *) NULL);
284 edit_error_dialog (_("Error"),
285 get_sys_error (tmp));
286 g_free (p);
287 g_free(tmp);
288 goto error_save;
290 g_free (p);
291 } else {
292 long buf;
293 buf = 0;
294 filelen = edit->last_byte;
295 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
296 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
297 != EDIT_BUF_SIZE) {
298 mc_close (fd);
299 goto error_save;
301 buf++;
303 if (mc_write
304 (fd, (char *) edit->buffers1[buf],
305 edit->curs1 & M_EDIT_BUF_SIZE) !=
306 (edit->curs1 & M_EDIT_BUF_SIZE)) {
307 filelen = -1;
308 } else if (edit->curs2) {
309 edit->curs2--;
310 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
311 if (mc_write
312 (fd,
313 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
314 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
315 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
316 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
317 filelen = -1;
318 } else {
319 while (--buf >= 0) {
320 if (mc_write
321 (fd, (char *) edit->buffers2[buf],
322 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
323 filelen = -1;
324 break;
328 edit->curs2++;
330 if (mc_close (fd))
331 goto error_save;
333 /* Update the file information, especially the mtime. */
334 if (mc_stat (savename, &edit->stat1) == -1)
335 goto error_save;
338 if (filelen != edit->last_byte)
339 goto error_save;
341 if (this_save_mode == EDIT_DO_BACKUP) {
342 assert (option_backup_ext != NULL);
343 tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
344 if (mc_rename (real_filename, tmp) == -1){
345 g_free(tmp);
346 goto error_save;
350 if (this_save_mode != EDIT_QUICK_SAVE)
351 if (mc_rename (savename, real_filename) == -1)
352 goto error_save;
353 g_free (savename);
354 g_free(real_filename);
355 return 1;
356 error_save:
357 /* FIXME: Is this safe ?
358 * if (this_save_mode != EDIT_QUICK_SAVE)
359 * mc_unlink (savename);
361 g_free(real_filename);
362 g_free (savename);
363 return 0;
366 void menu_save_mode_cmd (void)
368 #define DLG_X 38
369 #define DLG_Y 10
370 static char *str_result;
371 static int save_mode_new;
372 static const char *str[] =
374 N_("Quick save "),
375 N_("Safe save "),
376 N_("Do backups -->")};
378 static QuickWidget widgets[] =
380 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
381 B_CANCEL, 0, 0, NULL, NULL, NULL},
382 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
383 B_ENTER, 0, 0, NULL, NULL, NULL},
384 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
385 0, 0, &str_result, "edit-backup-ext", NULL, NULL},
386 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
387 0, 0, 0, NULL, NULL, NULL},
388 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
389 0, &save_mode_new, (char **) str, NULL, NULL, NULL},
390 NULL_QuickWidget};
391 static QuickDialog dialog =
392 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
393 widgets, 0};
394 static int i18n_flag = 0;
396 if (!i18n_flag) {
397 size_t i;
398 size_t maxlen = 0;
399 int dlg_x;
400 size_t l1;
402 /* OK/Cancel buttons */
403 l1 = str_term_width1 (_(widgets[0].text)) + str_term_width1 (_(widgets[1].text)) + 5;
404 maxlen = max (maxlen, l1);
406 for (i = 0; i < 3; i++ ) {
407 str[i] = _(str[i]);
408 maxlen = max (maxlen, (size_t) str_term_width1 (str[i]) + 7);
410 i18n_flag = 1;
412 dlg_x = maxlen + str_term_width1 (_(widgets[3].text)) + 5 + 1;
413 widgets[2].hotkey_pos = str_term_width1 (_(widgets[3].text)); /* input field length */
414 dlg_x = min (COLS, dlg_x);
415 dialog.xlen = dlg_x;
417 i = (dlg_x - l1)/3;
418 widgets[1].relative_x = i;
419 widgets[0].relative_x = i + str_term_width1 (_(widgets[1].text)) + i + 4;
421 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
423 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
424 widgets[i].x_divisions = dlg_x;
427 assert (option_backup_ext != NULL);
428 widgets[2].text = option_backup_ext;
429 widgets[4].value = option_save_mode;
430 if (quick_dialog (&dialog) != B_ENTER)
431 return;
432 option_save_mode = save_mode_new;
434 g_free (option_backup_ext);
435 option_backup_ext = str_result;
436 str_result = NULL;
439 void
440 edit_set_filename (WEdit *edit, const char *f)
442 g_free (edit->filename);
443 if (!f)
444 f = "";
445 edit->filename = g_strdup (f);
446 if (edit->dir == NULL && *f != PATH_SEP)
447 #ifdef USE_VFS
448 edit->dir = g_strdup (vfs_get_current_dir ());
449 #else
450 edit->dir = g_get_current_dir ();
451 #endif
454 /* Here we want to warn the users of overwriting an existing file,
455 but only if they have made a change to the filename */
456 /* returns 1 on success */
458 edit_save_as_cmd (WEdit *edit)
460 /* This heads the 'Save As' dialog box */
461 char *exp;
462 int save_lock = 0;
463 int different_filename = 0;
465 exp = input_expand_dialog (
466 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS, edit->filename);
467 edit_push_action (edit, KEY_PRESS + edit->start_display);
469 if (exp) {
470 if (!*exp) {
471 g_free (exp);
472 edit->force |= REDRAW_COMPLETELY;
473 return 0;
474 } else {
475 int rv;
476 if (strcmp (edit->filename, exp)) {
477 int file;
478 different_filename = 1;
479 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
480 /* the file exists */
481 mc_close (file);
482 /* Overwrite the current file or cancel the operation */
483 if (edit_query_dialog2
484 (_("Warning"),
485 _(" A file already exists with this name. "),
486 _("&Overwrite"), _("&Cancel"))) {
487 edit->force |= REDRAW_COMPLETELY;
488 g_free (exp);
489 return 0;
492 save_lock = edit_lock_file (exp);
493 } else {
494 /* filenames equal, check if already locked */
495 if (!edit->locked && !edit->delete_file)
496 save_lock = edit_lock_file (exp);
499 rv = edit_save_file (edit, exp);
500 switch (rv) {
501 case 1:
502 /* Succesful, so unlock both files */
503 if (different_filename) {
504 if (save_lock)
505 edit_unlock_file (exp);
506 if (edit->locked)
507 edit->locked = edit_unlock_file (edit->filename);
508 } else {
509 if (edit->locked || save_lock)
510 edit->locked = edit_unlock_file (edit->filename);
513 edit_set_filename (edit, exp);
514 g_free (exp);
515 edit->modified = 0;
516 edit->delete_file = 0;
517 if (different_filename)
518 edit_load_syntax (edit, NULL, option_syntax_type);
519 edit->force |= REDRAW_COMPLETELY;
520 return 1;
521 default:
522 edit_error_dialog (_(" Save As "),
523 get_sys_error (_
524 (" Cannot save file. ")));
525 /* fallthrough */
526 case -1:
527 /* Failed, so maintain modify (not save) lock */
528 if (save_lock)
529 edit_unlock_file (exp);
530 g_free (exp);
531 edit->force |= REDRAW_COMPLETELY;
532 return 0;
536 edit->force |= REDRAW_COMPLETELY;
537 return 0;
540 /* {{{ Macro stuff starts here */
542 /* creates a macro file if it doesn't exist */
543 static FILE *edit_open_macro_file (const char *r)
545 gchar *filename;
546 FILE *fd;
547 int file;
548 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
549 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
550 g_free(filename);
551 return 0;
553 close (file);
554 fd = fopen (filename, r);
555 g_free(filename);
556 return fd;
559 #define MAX_MACROS 1024
560 static int saved_macro[MAX_MACROS + 1];
561 static int saved_macros_loaded = 0;
564 This is just to stop the macro file be loaded over and over for keys
565 that aren't defined to anything. On slow systems this could be annoying.
567 static int
568 macro_exists (int k)
570 int i;
571 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
572 if (saved_macro[i] == k)
573 return i;
574 return -1;
577 /* returns 1 on error */
578 static int
579 edit_delete_macro (WEdit * edit, int k)
581 gchar *tmp, *tmp2;
582 struct macro macro[MAX_MACRO_LENGTH];
583 FILE *f, *g;
584 int s, i, n, j = 0;
586 (void) edit;
588 if (saved_macros_loaded)
589 if ((j = macro_exists (k)) < 0)
590 return 0;
591 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
592 g = fopen (tmp , "w");
593 g_free(tmp);
594 if (!g) {
595 edit_error_dialog (_(" Delete macro "),
596 get_sys_error (_(" Cannot open temp file ")));
597 return 1;
599 f = edit_open_macro_file ("r");
600 if (!f) {
601 edit_error_dialog (_(" Delete macro "),
602 get_sys_error (_(" Cannot open macro file ")));
603 fclose (g);
604 return 1;
606 for (;;) {
607 n = fscanf (f, ("key '%d 0': "), &s);
608 if (!n || n == EOF)
609 break;
610 n = 0;
611 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
612 n++;
613 fscanf (f, ";\n");
614 if (s != k) {
615 fprintf (g, ("key '%d 0': "), s);
616 for (i = 0; i < n; i++)
617 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
618 fprintf (g, ";\n");
621 fclose (f);
622 fclose (g);
623 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
624 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
625 if (rename ( tmp, tmp2) == -1) {
626 edit_error_dialog (_(" Delete macro "),
627 get_sys_error (_(" Cannot overwrite macro file ")));
628 g_free(tmp);
629 g_free(tmp2);
630 return 1;
632 g_free(tmp);
633 g_free(tmp2);
635 if (saved_macros_loaded)
636 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
637 return 0;
640 /* returns 0 on error */
641 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
643 FILE *f;
644 int s, i;
646 edit_push_action (edit, KEY_PRESS + edit->start_display);
647 s = editcmd_dialog_raw_key_query (_(" Save macro "),
648 _(" Press the macro's new hotkey: "), 1);
649 edit->force |= REDRAW_COMPLETELY;
650 if (s) {
651 if (edit_delete_macro (edit, s))
652 return 0;
653 f = edit_open_macro_file ("a+");
654 if (f) {
655 fprintf (f, ("key '%d 0': "), s);
656 for (i = 0; i < n; i++)
657 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
658 fprintf (f, ";\n");
659 fclose (f);
660 if (saved_macros_loaded) {
661 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
662 saved_macro[i] = s;
664 return 1;
665 } else
666 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
668 return 0;
671 void edit_delete_macro_cmd (WEdit * edit)
673 int command;
675 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
676 _ (" Press macro hotkey: "), 1);
678 if (!command)
679 return;
681 edit_delete_macro (edit, command);
684 /* return 0 on error */
685 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
687 FILE *f;
688 int s, i = 0, found = 0;
690 (void) edit;
692 if (saved_macros_loaded)
693 if (macro_exists (k) < 0)
694 return 0;
696 if ((f = edit_open_macro_file ("r"))) {
697 struct macro dummy;
698 do {
699 int u;
700 u = fscanf (f, ("key '%d 0': "), &s);
701 if (!u || u == EOF)
702 break;
703 if (!saved_macros_loaded)
704 saved_macro[i++] = s;
705 if (!found) {
706 *n = 0;
707 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
708 (*n)++;
709 } else {
710 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
712 fscanf (f, ";\n");
713 if (s == k)
714 found = 1;
715 } while (!found || !saved_macros_loaded);
716 if (!saved_macros_loaded) {
717 saved_macro[i] = 0;
718 saved_macros_loaded = 1;
720 fclose (f);
721 return found;
722 } else
723 edit_error_dialog (_(" Load macro "),
724 get_sys_error (_(" Cannot open macro file ")));
725 return 0;
728 /* }}} Macro stuff starts here */
730 /* returns 1 on success */
731 int edit_save_confirm_cmd (WEdit * edit)
733 gchar *f = NULL;
735 if (edit_confirm_save) {
736 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
737 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
738 g_free(f);
739 return 0;
741 g_free(f);
743 return edit_save_cmd (edit);
747 /* returns 1 on success */
748 static int
749 edit_save_cmd (WEdit *edit)
751 int res, save_lock = 0;
753 if (!edit->locked && !edit->delete_file)
754 save_lock = edit_lock_file (edit->filename);
755 res = edit_save_file (edit, edit->filename);
757 /* Maintain modify (not save) lock on failure */
758 if ((res > 0 && edit->locked) || save_lock)
759 edit->locked = edit_unlock_file (edit->filename);
761 /* On failure try 'save as', it does locking on its own */
762 if (!res)
763 return edit_save_as_cmd (edit);
764 edit->force |= REDRAW_COMPLETELY;
765 if (res > 0) {
766 edit->delete_file = 0;
767 edit->modified = 0;
770 return 1;
774 /* returns 1 on success */
775 int edit_new_cmd (WEdit * edit)
777 if (edit->modified) {
778 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
779 edit->force |= REDRAW_COMPLETELY;
780 return 0;
783 edit->force |= REDRAW_COMPLETELY;
785 return edit_renew (edit); /* if this gives an error, something has really screwed up */
788 /* returns 1 on error */
789 static int
790 edit_load_file_from_filename (WEdit * edit, char *exp)
792 int prev_locked = edit->locked;
793 char *prev_filename = g_strdup (edit->filename);
795 if (!edit_reload (edit, exp)) {
796 g_free (prev_filename);
797 return 1;
800 if (prev_locked)
801 edit_unlock_file (prev_filename);
802 g_free (prev_filename);
803 return 0;
806 static void
807 edit_load_syntax_file (WEdit * edit)
809 char *extdir;
810 int dir = 0;
812 if (geteuid () == 0) {
813 dir = query_dialog (_("Syntax file edit"),
814 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
815 _("&User"), _("&System Wide"));
818 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
819 if (!exist_file(extdir)) {
820 g_free (extdir);
821 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
824 if (dir == 0) {
825 char *buffer;
827 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
828 check_for_default (extdir, buffer);
829 edit_load_file_from_filename (edit, buffer);
830 g_free (buffer);
831 } else if (dir == 1)
832 edit_load_file_from_filename (edit, extdir);
834 g_free (extdir);
837 static void
838 edit_load_menu_file (WEdit * edit)
840 char *buffer;
841 char *menufile;
842 int dir = 0;
844 dir = query_dialog (
845 _(" Menu edit "),
846 _(" Which menu file do you want to edit? "), D_NORMAL,
847 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
850 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
852 if (!exist_file (menufile)) {
853 g_free (menufile);
854 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
857 switch (dir) {
858 case 0:
859 buffer = g_strdup (EDIT_LOCAL_MENU);
860 check_for_default (menufile, buffer);
861 chmod (buffer, 0600);
862 break;
864 case 1:
865 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
866 check_for_default (menufile, buffer);
867 break;
869 case 2:
870 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
871 if (!exist_file (buffer)) {
872 g_free (buffer);
873 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
875 break;
877 default:
878 g_free (menufile);
879 return;
882 edit_load_file_from_filename (edit, buffer);
884 g_free (buffer);
885 g_free (menufile);
889 edit_load_cmd (WEdit *edit, edit_current_file_t what)
891 char *exp;
893 if (edit->modified
894 && (edit_query_dialog2
895 (_("Warning"),
896 _(" Current text was modified without a file save. \n"
897 " Continue discards these changes. "),
898 _("C&ontinue"), _("&Cancel")) == 1)) {
899 edit->force |= REDRAW_COMPLETELY;
900 return 0;
903 switch (what) {
904 case EDIT_FILE_COMMON:
905 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
906 MC_HISTORY_EDIT_LOAD, edit->filename);
908 if (exp) {
909 if (*exp)
910 edit_load_file_from_filename (edit, exp);
911 g_free (exp);
913 break;
915 case EDIT_FILE_SYNTAX:
916 edit_load_syntax_file (edit);
917 break;
919 case EDIT_FILE_MENU:
920 edit_load_menu_file (edit);
921 break;
923 default:
924 break;
927 edit->force |= REDRAW_COMPLETELY;
928 return 0;
932 if mark2 is -1 then marking is from mark1 to the cursor.
933 Otherwise its between the markers. This handles this.
934 Returns 1 if no text is marked.
936 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
938 if (edit->mark1 != edit->mark2) {
939 if (edit->mark2 >= 0) {
940 *start_mark = min (edit->mark1, edit->mark2);
941 *end_mark = max (edit->mark1, edit->mark2);
942 } else {
943 *start_mark = min (edit->mark1, edit->curs1);
944 *end_mark = max (edit->mark1, edit->curs1);
945 edit->column2 = edit->curs_col;
947 return 0;
948 } else {
949 *start_mark = *end_mark = 0;
950 edit->column2 = edit->column1 = 0;
951 return 1;
955 #define space_width 1
957 static void
958 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
960 long cursor;
961 int i, col;
962 cursor = edit->curs1;
963 col = edit_get_col (edit);
964 for (i = 0; i < size; i++) {
965 if (data[i] == '\n') { /* fill in and move to next line */
966 int l;
967 long p;
968 if (edit_get_byte (edit, edit->curs1) != '\n') {
969 l = width - (edit_get_col (edit) - col);
970 while (l > 0) {
971 edit_insert (edit, ' ');
972 l -= space_width;
975 for (p = edit->curs1;; p++) {
976 if (p == edit->last_byte) {
977 edit_cursor_move (edit, edit->last_byte - edit->curs1);
978 edit_insert_ahead (edit, '\n');
979 p++;
980 break;
982 if (edit_get_byte (edit, p) == '\n') {
983 p++;
984 break;
987 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
988 l = col - edit_get_col (edit);
989 while (l >= space_width) {
990 edit_insert (edit, ' ');
991 l -= space_width;
993 continue;
995 edit_insert (edit, data[i]);
997 edit_cursor_move (edit, cursor - edit->curs1);
1001 void
1002 edit_block_copy_cmd (WEdit *edit)
1004 long start_mark, end_mark, current = edit->curs1;
1005 int size;
1006 unsigned char *copy_buf;
1008 edit_update_curs_col (edit);
1009 if (eval_marks (edit, &start_mark, &end_mark))
1010 return;
1012 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1014 /* all that gets pushed are deletes hence little space is used on the stack */
1016 edit_push_markers (edit);
1018 if (column_highlighting) {
1019 edit_insert_column_of_text (edit, copy_buf, size,
1020 abs (edit->column2 - edit->column1));
1021 } else {
1022 while (size--)
1023 edit_insert_ahead (edit, copy_buf[size]);
1026 g_free (copy_buf);
1027 edit_scroll_screen_over_cursor (edit);
1029 if (column_highlighting) {
1030 edit_set_markers (edit, 0, 0, 0, 0);
1031 edit_push_action (edit, COLUMN_ON);
1032 column_highlighting = 0;
1033 } else if (start_mark < current && end_mark > current)
1034 edit_set_markers (edit, start_mark,
1035 end_mark + end_mark - start_mark, 0, 0);
1037 edit->force |= REDRAW_PAGE;
1041 void
1042 edit_block_move_cmd (WEdit *edit)
1044 long count;
1045 long current;
1046 unsigned char *copy_buf;
1047 long start_mark, end_mark;
1048 int deleted = 0;
1049 int x = 0;
1051 if (eval_marks (edit, &start_mark, &end_mark))
1052 return;
1053 if (column_highlighting) {
1054 edit_update_curs_col (edit);
1055 x = edit->curs_col;
1056 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1057 if ((x > edit->column1 && x < edit->column2)
1058 || (x > edit->column2 && x < edit->column1))
1059 return;
1060 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1061 return;
1063 if ((end_mark - start_mark) > option_max_undo / 2)
1064 if (edit_query_dialog2
1065 (_("Warning"),
1067 (" Block is large, you may not be able to undo this action. "),
1068 _("C&ontinue"), _("&Cancel")))
1069 return;
1071 edit_push_markers (edit);
1072 current = edit->curs1;
1073 if (column_highlighting) {
1074 int size, c1, c2, line;
1075 line = edit->curs_line;
1076 if (edit->mark2 < 0)
1077 edit_mark_cmd (edit, 0);
1078 c1 = min (edit->column1, edit->column2);
1079 c2 = max (edit->column1, edit->column2);
1080 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1081 if (x < c2) {
1082 edit_block_delete_cmd (edit);
1083 deleted = 1;
1085 edit_move_to_line (edit, line);
1086 edit_cursor_move (edit,
1087 edit_move_forward3 (edit,
1088 edit_bol (edit, edit->curs1),
1089 x, 0) - edit->curs1);
1090 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1091 if (!deleted) {
1092 line = edit->curs_line;
1093 edit_update_curs_col (edit);
1094 x = edit->curs_col;
1095 edit_block_delete_cmd (edit);
1096 edit_move_to_line (edit, line);
1097 edit_cursor_move (edit,
1098 edit_move_forward3 (edit,
1099 edit_bol (edit,
1100 edit->curs1),
1101 x, 0) - edit->curs1);
1103 edit_set_markers (edit, 0, 0, 0, 0);
1104 edit_push_action (edit, COLUMN_ON);
1105 column_highlighting = 0;
1106 } else {
1107 copy_buf = g_malloc (end_mark - start_mark);
1108 edit_cursor_move (edit, start_mark - edit->curs1);
1109 edit_scroll_screen_over_cursor (edit);
1110 count = start_mark;
1111 while (count < end_mark) {
1112 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1113 count++;
1115 edit_scroll_screen_over_cursor (edit);
1116 edit_cursor_move (edit,
1117 current - edit->curs1 -
1118 (((current - edit->curs1) >
1119 0) ? end_mark - start_mark : 0));
1120 edit_scroll_screen_over_cursor (edit);
1121 while (count-- > start_mark)
1122 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1123 edit_set_markers (edit, edit->curs1,
1124 edit->curs1 + end_mark - start_mark, 0, 0);
1126 edit_scroll_screen_over_cursor (edit);
1127 g_free (copy_buf);
1128 edit->force |= REDRAW_PAGE;
1131 static void
1132 edit_delete_column_of_text (WEdit * edit)
1134 long p, q, r, m1, m2;
1135 int b, c, d;
1136 int n;
1138 eval_marks (edit, &m1, &m2);
1139 n = edit_move_forward (edit, m1, 0, m2) + 1;
1140 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1141 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1143 b = min (c, d);
1144 c = max (c, d);
1146 while (n--) {
1147 r = edit_bol (edit, edit->curs1);
1148 p = edit_move_forward3 (edit, r, b, 0);
1149 q = edit_move_forward3 (edit, r, c, 0);
1150 if (p < m1)
1151 p = m1;
1152 if (q > m2)
1153 q = m2;
1154 edit_cursor_move (edit, p - edit->curs1);
1155 while (q > p) { /* delete line between margins */
1156 if (edit_get_byte (edit, edit->curs1) != '\n')
1157 edit_delete (edit, 1);
1158 q--;
1160 if (n) /* move to next line except on the last delete */
1161 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1165 /* if success return 0 */
1166 static int
1167 edit_block_delete (WEdit *edit)
1169 long count;
1170 long start_mark, end_mark;
1171 if (eval_marks (edit, &start_mark, &end_mark))
1172 return 0;
1173 if (column_highlighting && edit->mark2 < 0)
1174 edit_mark_cmd (edit, 0);
1175 if ((end_mark - start_mark) > option_max_undo / 2) {
1176 /* Warning message with a query to continue or cancel the operation */
1177 if (edit_query_dialog2
1178 (_("Warning"),
1180 (" Block is large, you may not be able to undo this action. "),
1181 _("C&ontinue"), _("&Cancel"))) {
1182 return 1;
1185 edit_push_markers (edit);
1186 edit_cursor_move (edit, start_mark - edit->curs1);
1187 edit_scroll_screen_over_cursor (edit);
1188 count = start_mark;
1189 if (start_mark < end_mark) {
1190 if (column_highlighting) {
1191 if (edit->mark2 < 0)
1192 edit_mark_cmd (edit, 0);
1193 edit_delete_column_of_text (edit);
1194 } else {
1195 while (count < end_mark) {
1196 edit_delete (edit, 1);
1197 count++;
1201 edit_set_markers (edit, 0, 0, 0, 0);
1202 edit->force |= REDRAW_PAGE;
1203 return 0;
1206 /* returns 1 if canceelled by user */
1207 int edit_block_delete_cmd (WEdit * edit)
1209 long start_mark, end_mark;
1210 if (eval_marks (edit, &start_mark, &end_mark)) {
1211 edit_delete_line (edit);
1212 return 0;
1214 return edit_block_delete (edit);
1217 #define INPUT_INDEX 9
1219 static gboolean
1220 editcmd_find (WEdit *edit, gsize *len)
1222 gsize search_start = edit->search_start;
1223 gsize search_end;
1225 if (edit->replace_backwards) {
1226 search_end = edit->curs1-1;
1227 while ((int) search_start >= 0) {
1228 if (search_end - search_start > edit->search->original_len && mc_search_is_fixed_search_str(edit->search))
1229 search_end = search_start + edit->search->original_len +1;
1230 if ( mc_search_run(edit->search, (void *) edit, search_start, search_end, len))
1232 return TRUE;
1234 search_start--;
1236 edit->search->error_str = g_strdup(_(" Search string not found "));
1237 } else {
1238 return mc_search_run(edit->search, (void *) edit, edit->search_start, edit->last_byte, len);
1240 return FALSE;
1244 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1245 (and the above) routines to work properly - paul */
1247 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1249 static char *
1250 edit_replace_cmd__conv_to_display(char *str)
1252 #ifdef HAVE_CHARSET
1253 GString *tmp;
1254 tmp = str_convert_to_display (str);
1256 if (tmp && tmp->len){
1257 g_free(str);
1258 str = tmp->str;
1260 g_string_free (tmp, FALSE);
1261 return str;
1262 #else
1263 return g_strdup(str);
1264 #endif
1267 static char *
1268 edit_replace_cmd__conv_to_input(char *str)
1270 #ifdef HAVE_CHARSET
1271 GString *tmp;
1272 tmp = str_convert_to_input (str);
1274 if (tmp && tmp->len){
1275 g_free(str);
1276 str = tmp->str;
1278 g_string_free (tmp, FALSE);
1279 return str;
1280 #else
1281 return g_strdup(str);
1282 #endif
1284 /* call with edit = 0 before shutdown to close memory leaks */
1285 void
1286 edit_replace_cmd (WEdit *edit, int again)
1288 /* 1 = search string, 2 = replace with */
1289 static char *saved1 = NULL; /* saved default[123] */
1290 static char *saved2 = NULL;
1291 char *input1 = NULL; /* user input from the dialog */
1292 char *input2 = NULL;
1293 char *str_for_prompt_dialog = NULL;
1294 int replace_yes;
1295 long times_replaced = 0, last_search;
1296 gboolean once_found = FALSE;
1298 if (!edit) {
1299 g_free (saved1), saved1 = NULL;
1300 g_free (saved2), saved2 = NULL;
1301 return;
1304 last_search = edit->last_byte;
1306 edit->force |= REDRAW_COMPLETELY;
1308 if (again && !saved1 && !saved2)
1309 again = 0;
1311 if (again) {
1312 input1 = g_strdup (saved1 ? saved1 : "");
1313 input2 = g_strdup (saved2 ? saved2 : "");
1314 } else {
1315 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1316 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1318 edit_push_action (edit, KEY_PRESS + edit->start_display);
1320 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1322 g_free (disp1);
1323 g_free (disp2);
1325 str_for_prompt_dialog = g_strdup(input2);
1327 if (input1 == NULL || *input1 == '\0') {
1328 edit->force = REDRAW_COMPLETELY;
1329 goto cleanup;
1332 input1 = edit_replace_cmd__conv_to_input(input1);
1333 input2 = edit_replace_cmd__conv_to_input(input2);
1335 g_free (saved1), saved1 = g_strdup (input1);
1336 g_free (saved2), saved2 = g_strdup (input2);
1338 if (edit->search)
1340 mc_search_free(edit->search);
1341 edit->search = NULL;
1345 if (!edit->search)
1347 edit->search = mc_search_new(input1, -1);
1348 if (edit->search == NULL)
1350 edit->search_start = edit->curs1;
1351 return;
1353 edit->search->search_type = edit->search_type;
1354 edit->search->is_all_charsets = edit->all_codepages;
1355 edit->search->is_case_sentitive = edit->replace_case;
1356 edit->search->search_fn = edit_search_cmd_callback;
1359 if (edit->found_len && edit->search_start == edit->found_start + 1
1360 && edit->replace_backwards)
1361 edit->search_start--;
1363 if (edit->found_len && edit->search_start == edit->found_start - 1
1364 && !edit->replace_backwards)
1365 edit->search_start++;
1367 do {
1368 gsize len = 0;
1369 long new_start;
1371 if (! editcmd_find(edit, &len))
1373 if (!(edit->search->error == MC_SEARCH_E_OK || (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
1375 edit_error_dialog (_ ("Search"), edit->search->error_str);
1377 break;
1379 once_found = TRUE;
1380 new_start = edit->search->normal_offset;
1382 edit->search_start = new_start = edit->search->normal_offset;
1383 /*returns negative on not found or error in pattern */
1385 if (edit->search_start >= 0) {
1386 int i;
1388 edit->found_start = edit->search_start;
1389 i = edit->found_len = len;
1391 edit_cursor_move (edit, edit->search_start - edit->curs1);
1392 edit_scroll_screen_over_cursor (edit);
1394 replace_yes = 1;
1396 if (edit->replace_mode==0) {
1397 int l;
1398 l = edit->curs_row - edit->num_widget_lines / 3;
1399 if (l > 0)
1400 edit_scroll_downward (edit, l);
1401 if (l < 0)
1402 edit_scroll_upward (edit, -l);
1404 edit_scroll_screen_over_cursor (edit);
1405 edit->force |= REDRAW_PAGE;
1406 edit_render_keypress (edit);
1408 /*so that undo stops at each query */
1409 edit_push_key_press (edit);
1411 switch (editcmd_dialog_replace_prompt_show (edit, str_for_prompt_dialog, /* and prompt 2/3 down */
1413 -1)) {
1414 case B_ENTER:
1415 break;
1416 case B_SKIP_REPLACE:
1417 replace_yes = 0;
1418 break;
1419 case B_REPLACE_ALL:
1420 edit->replace_mode=1;
1421 break;
1422 case B_REPLACE_ONE:
1423 break;
1424 case B_CANCEL:
1425 replace_yes = 0;
1426 break;
1429 if (replace_yes) { /* delete then insert new */
1430 GString *repl_str, *tmp_str;
1431 tmp_str = g_string_new(input2);
1433 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1434 g_string_free(tmp_str, TRUE);
1435 if (edit->search->error != MC_SEARCH_E_OK)
1437 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1438 break;
1441 while (i--)
1442 edit_delete (edit, 1);
1444 while (++i < repl_str->len)
1445 edit_insert (edit, repl_str->str[i]);
1447 g_string_free(repl_str, TRUE);
1448 edit->found_len = i;
1450 /* so that we don't find the same string again */
1451 if (edit->replace_backwards) {
1452 last_search = edit->search_start;
1453 edit->search_start--;
1454 } else {
1455 edit->search_start += i;
1456 last_search = edit->last_byte;
1458 edit_scroll_screen_over_cursor (edit);
1459 } else {
1460 const char *msg = _(" Replace ");
1461 /* try and find from right here for next search */
1462 edit->search_start = edit->curs1;
1463 edit_update_curs_col (edit);
1465 edit->force |= REDRAW_PAGE;
1466 edit_render_keypress (edit);
1467 if (times_replaced) {
1468 message (D_NORMAL, msg, _(" %ld replacements made. "),
1469 times_replaced);
1470 } else
1471 query_dialog (msg, _(" Search string not found "),
1472 D_NORMAL, 1, _("&OK"));
1473 edit->replace_mode = -1;
1475 } while (edit->replace_mode >0);
1477 edit->force = REDRAW_COMPLETELY;
1478 edit_scroll_screen_over_cursor (edit);
1479 cleanup:
1480 g_free (str_for_prompt_dialog);
1481 g_free (input1);
1482 g_free (input2);
1486 void edit_search_cmd (WEdit * edit, int again)
1488 char *search_string = NULL, *search_string_dup = NULL;
1490 gsize len = 0;
1492 if (!edit)
1493 return;
1495 if (edit->search != NULL)
1496 search_string_dup = search_string = g_strndup(edit->search->original, edit->search->original_len);
1498 if (!again)
1500 #ifdef HAVE_CHARSET
1501 GString *tmp;
1502 if (search_string && *search_string)
1504 tmp = str_convert_to_display (search_string);
1506 g_free(search_string_dup);
1507 search_string_dup = NULL;
1509 if (tmp && tmp->len)
1510 search_string = search_string_dup = tmp->str;
1511 g_string_free (tmp, FALSE);
1513 #endif /* HAVE_CHARSET */
1514 editcmd_dialog_search_show (edit, &search_string);
1515 #ifdef HAVE_CHARSET
1516 if (search_string && *search_string)
1518 tmp = str_convert_to_input (search_string);
1519 if (tmp && tmp->len)
1520 search_string = tmp->str;
1522 g_string_free (tmp, FALSE);
1524 if (search_string_dup)
1525 g_free(search_string_dup);
1527 #endif /* HAVE_CHARSET */
1529 edit_push_action (edit, KEY_PRESS + edit->start_display);
1531 if (!search_string)
1533 edit->force |= REDRAW_COMPLETELY;
1534 edit_scroll_screen_over_cursor (edit);
1535 return;
1538 if (edit->search)
1540 mc_search_free(edit->search);
1541 edit->search = NULL;
1545 if (!edit->search)
1547 edit->search = mc_search_new(search_string, -1);
1548 if (edit->search == NULL)
1550 edit->search_start = edit->curs1;
1551 return;
1553 edit->search->search_type = edit->search_type;
1554 edit->search->is_all_charsets = edit->all_codepages;
1555 edit->search->is_case_sentitive = edit->replace_case;
1556 edit->search->search_fn = edit_search_cmd_callback;
1559 if (search_create_bookmark)
1561 edit_search_cmd_search_create_bookmark(edit);
1563 else
1565 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1566 edit->search_start--;
1568 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1569 edit->search_start++;
1572 if (editcmd_find(edit, &len))
1574 edit->found_start = edit->search_start = edit->search->normal_offset;
1575 edit->found_len = len;
1577 edit_cursor_move (edit, edit->search_start - edit->curs1);
1578 edit_scroll_screen_over_cursor (edit);
1579 if (edit->replace_backwards)
1580 edit->search_start--;
1581 else
1582 edit->search_start++;
1584 else
1586 edit->search_start = edit->curs1;
1587 if (edit->search->error_str)
1588 edit_error_dialog (_ ("Search"), edit->search->error_str);
1592 edit->force |= REDRAW_COMPLETELY;
1593 edit_scroll_screen_over_cursor (edit);
1598 * Check if it's OK to close the editor. If there are unsaved changes,
1599 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1602 edit_ok_to_exit (WEdit *edit)
1604 if (!edit->modified)
1605 return 1;
1607 switch (edit_query_dialog3
1608 (_("Quit"), _(" File was modified, Save with exit? "),
1609 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1610 case 1:
1611 edit_push_markers (edit);
1612 edit_set_markers (edit, 0, 0, 0, 0);
1613 if (!edit_save_cmd (edit))
1614 return 0;
1615 break;
1616 case 2:
1617 break;
1618 case 0:
1619 case -1:
1620 return 0;
1623 return 1;
1627 #define TEMP_BUF_LEN 1024
1629 /* Return a null terminated length of text. Result must be g_free'd */
1630 static unsigned char *
1631 edit_get_block (WEdit *edit, long start, long finish, int *l)
1633 unsigned char *s, *r;
1634 r = s = g_malloc (finish - start + 1);
1635 if (column_highlighting) {
1636 *l = 0;
1637 /* copy from buffer, excluding chars that are out of the column 'margins' */
1638 while (start < finish) {
1639 int c, x;
1640 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1641 start);
1642 c = edit_get_byte (edit, start);
1643 if ((x >= edit->column1 && x < edit->column2)
1644 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1645 *s++ = c;
1646 (*l)++;
1648 start++;
1650 } else {
1651 *l = finish - start;
1652 while (start < finish)
1653 *s++ = edit_get_byte (edit, start++);
1655 *s = 0;
1656 return r;
1659 /* save block, returns 1 on success */
1661 edit_save_block (WEdit * edit, const char *filename, long start,
1662 long finish)
1664 int len, file;
1666 if ((file =
1667 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1668 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1669 return 0;
1671 if (column_highlighting) {
1672 unsigned char *block, *p;
1673 int r;
1674 p = block = edit_get_block (edit, start, finish, &len);
1675 while (len) {
1676 r = mc_write (file, p, len);
1677 if (r < 0)
1678 break;
1679 p += r;
1680 len -= r;
1682 g_free (block);
1683 } else {
1684 unsigned char *buf;
1685 int i = start, end;
1686 len = finish - start;
1687 buf = g_malloc (TEMP_BUF_LEN);
1688 while (start != finish) {
1689 end = min (finish, start + TEMP_BUF_LEN);
1690 for (; i < end; i++)
1691 buf[i - start] = edit_get_byte (edit, i);
1692 len -= mc_write (file, (char *) buf, end - start);
1693 start = end;
1695 g_free (buf);
1697 mc_close (file);
1698 if (len)
1699 return 0;
1700 return 1;
1703 /* copies a block to clipboard file */
1704 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1706 int ret;
1707 gchar *tmp;
1708 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1709 ret = edit_save_block (edit, tmp, start, finish);
1710 g_free(tmp);
1711 return ret;
1715 void edit_paste_from_history (WEdit *edit)
1717 (void) edit;
1718 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1721 int edit_copy_to_X_buf_cmd (WEdit * edit)
1723 long start_mark, end_mark;
1724 if (eval_marks (edit, &start_mark, &end_mark))
1725 return 0;
1726 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1727 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1728 return 1;
1730 edit_mark_cmd (edit, 1);
1731 return 0;
1734 int edit_cut_to_X_buf_cmd (WEdit * edit)
1736 long start_mark, end_mark;
1737 if (eval_marks (edit, &start_mark, &end_mark))
1738 return 0;
1739 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1740 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1741 return 1;
1743 edit_block_delete_cmd (edit);
1744 edit_mark_cmd (edit, 1);
1745 return 0;
1748 void edit_paste_from_X_buf_cmd (WEdit * edit)
1750 gchar *tmp;
1751 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1752 edit_insert_file (edit, tmp);
1753 g_free(tmp);
1758 * Ask user for the line and go to that line.
1759 * Negative numbers mean line from the end (i.e. -1 is the last line).
1761 void
1762 edit_goto_cmd (WEdit *edit)
1764 char *f;
1765 static long line = 0; /* line as typed, saved as default */
1766 long l;
1767 char *error;
1768 char s[32];
1770 g_snprintf (s, sizeof (s), "%ld", line);
1771 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1772 line ? s : "");
1773 if (!f)
1774 return;
1776 if (!*f) {
1777 g_free (f);
1778 return;
1781 l = strtol (f, &error, 0);
1782 if (*error) {
1783 g_free (f);
1784 return;
1787 line = l;
1788 if (l < 0)
1789 l = edit->total_lines + l + 2;
1790 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
1791 edit_move_to_line (edit, l - 1);
1792 edit->force |= REDRAW_COMPLETELY;
1793 g_free (f);
1797 /* Return 1 on success */
1799 edit_save_block_cmd (WEdit *edit)
1801 long start_mark, end_mark;
1802 char *exp, *tmp;
1804 if (eval_marks (edit, &start_mark, &end_mark))
1805 return 1;
1807 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1808 exp =
1809 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
1810 MC_HISTORY_EDIT_SAVE_BLOCK,
1811 tmp);
1812 g_free(tmp);
1813 edit_push_action (edit, KEY_PRESS + edit->start_display);
1814 if (exp) {
1815 if (!*exp) {
1816 g_free (exp);
1817 return 0;
1818 } else {
1819 if (edit_save_block (edit, exp, start_mark, end_mark)) {
1820 g_free (exp);
1821 edit->force |= REDRAW_COMPLETELY;
1822 return 1;
1823 } else {
1824 g_free (exp);
1825 edit_error_dialog (_(" Save Block "),
1826 get_sys_error (_
1827 (" Cannot save file. ")));
1831 edit->force |= REDRAW_COMPLETELY;
1832 return 0;
1836 /* returns 1 on success */
1838 edit_insert_file_cmd (WEdit *edit)
1840 gchar *tmp;
1841 char *exp;
1843 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1844 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
1845 MC_HISTORY_EDIT_INSERT_FILE,
1846 tmp);
1847 g_free(tmp);
1848 edit_push_action (edit, KEY_PRESS + edit->start_display);
1849 if (exp) {
1850 if (!*exp) {
1851 g_free (exp);
1852 return 0;
1853 } else {
1854 if (edit_insert_file (edit, exp)) {
1855 g_free (exp);
1856 edit->force |= REDRAW_COMPLETELY;
1857 return 1;
1858 } else {
1859 g_free (exp);
1860 edit_error_dialog (_(" Insert File "),
1861 get_sys_error (_
1862 (" Cannot insert file. ")));
1866 edit->force |= REDRAW_COMPLETELY;
1867 return 0;
1870 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
1871 int edit_sort_cmd (WEdit * edit)
1873 static char *old = 0;
1874 char *exp, *tmp;
1875 long start_mark, end_mark;
1876 int e;
1878 if (eval_marks (edit, &start_mark, &end_mark)) {
1879 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
1880 return 0;
1883 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
1884 edit_save_block (edit, tmp, start_mark, end_mark);
1885 g_free(tmp);
1887 exp = input_dialog (_(" Run Sort "),
1888 _(" Enter sort options (see manpage) separated by whitespace: "),
1889 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
1891 if (!exp)
1892 return 1;
1893 g_free (old);
1894 old = exp;
1895 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
1896 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
1897 e = system (tmp);
1898 g_free(tmp);
1899 if (e) {
1900 if (e == -1 || e == 127) {
1901 edit_error_dialog (_(" Sort "),
1902 get_sys_error (_(" Cannot execute sort command ")));
1903 } else {
1904 char q[8];
1905 sprintf (q, "%d ", e);
1906 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
1907 edit_error_dialog (_(" Sort "), tmp);
1908 g_free(tmp);
1910 return -1;
1913 edit->force |= REDRAW_COMPLETELY;
1915 if (edit_block_delete_cmd (edit))
1916 return 1;
1917 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
1918 edit_insert_file (edit, tmp);
1919 g_free(tmp);
1920 return 0;
1924 * Ask user for a command, execute it and paste its output back to the
1925 * editor.
1928 edit_ext_cmd (WEdit *edit)
1930 char *exp, *tmp;
1931 int e;
1933 exp =
1934 input_dialog (_("Paste output of external command"),
1935 _("Enter shell command(s):"),
1936 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
1938 if (!exp)
1939 return 1;
1941 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
1942 e = system (tmp);
1943 g_free(tmp);
1944 g_free (exp);
1946 if (e) {
1947 edit_error_dialog (_("External command"),
1948 get_sys_error (_("Cannot execute command")));
1949 return -1;
1952 edit->force |= REDRAW_COMPLETELY;
1953 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
1954 edit_insert_file (edit, tmp);
1955 g_free(tmp);
1956 return 0;
1959 /* if block is 1, a block must be highlighted and the shell command
1960 processes it. If block is 0 the shell command is a straight system
1961 command, that just produces some output which is to be inserted */
1962 void
1963 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
1965 long start_mark, end_mark;
1966 char buf[BUFSIZ];
1967 FILE *script_home = NULL;
1968 FILE *script_src = NULL;
1969 FILE *block_file = NULL;
1970 gchar *o, *h, *b, *tmp;
1971 char *quoted_name = NULL;
1973 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
1974 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
1975 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
1977 if (!(script_home = fopen (h, "r"))) {
1978 if (!(script_home = fopen (h, "w"))) {
1979 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
1980 edit_error_dialog ("", get_sys_error (tmp));
1981 g_free(tmp);
1982 goto edit_block_process_cmd__EXIT;
1984 if (!(script_src = fopen (o, "r"))) {
1985 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
1986 if (!(script_src = fopen (o, "r"))) {
1987 fclose (script_home);
1988 unlink (h);
1989 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
1990 edit_error_dialog ("", get_sys_error (tmp));
1991 g_free(tmp);
1992 goto edit_block_process_cmd__EXIT;
1995 while (fgets (buf, sizeof (buf), script_src))
1996 fputs (buf, script_home);
1997 if (fclose (script_home)) {
1998 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
1999 edit_error_dialog ("", get_sys_error (tmp));
2000 g_free(tmp);
2001 goto edit_block_process_cmd__EXIT;
2003 chmod (h, 0700);
2004 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2005 edit_error_dialog ("", get_sys_error (tmp));
2006 g_free(tmp);
2009 open_error_pipe ();
2011 if (block) { /* for marked block run indent formatter */
2012 if (eval_marks (edit, &start_mark, &end_mark)) {
2013 edit_error_dialog (_("Process block"),
2015 (" You must first highlight a block of text. "));
2016 goto edit_block_process_cmd__EXIT;
2018 edit_save_block (edit, b, start_mark, end_mark);
2019 quoted_name = name_quote (edit->filename, 0);
2021 * Run script.
2022 * Initial space is to avoid polluting bash history.
2023 * Arguments:
2024 * $1 - name of the edited file (to check its extension etc).
2025 * $2 - file containing the current block.
2026 * $3 - file where error messages should be put
2027 * (for compatibility with old scripts).
2029 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2030 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2031 system (tmp);
2032 g_free(tmp);
2033 } else {
2035 * No block selected, just execute the command for the file.
2036 * Arguments:
2037 * $1 - name of the edited file.
2039 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2040 quoted_name, (char *) NULL);
2041 system (tmp);
2042 g_free(tmp);
2044 g_free (quoted_name);
2045 close_error_pipe (D_NORMAL, NULL);
2047 edit_refresh_cmd (edit);
2048 edit->force |= REDRAW_COMPLETELY;
2050 /* insert result block */
2051 if (block) {
2052 if (edit_block_delete_cmd (edit))
2053 goto edit_block_process_cmd__EXIT;
2054 edit_insert_file (edit, b);
2055 if ((block_file = fopen (b, "w")))
2056 fclose (block_file);
2057 goto edit_block_process_cmd__EXIT;
2059 edit_block_process_cmd__EXIT:
2060 g_free(b);
2061 g_free(h);
2062 g_free(o);
2063 return;
2066 /* prints at the cursor */
2067 /* returns the number of chars printed */
2068 int edit_print_string (WEdit * e, const char *s)
2070 int i = 0;
2071 while (s[i])
2072 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2073 e->force |= REDRAW_COMPLETELY;
2074 edit_update_screen (e);
2075 return i;
2079 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2081 FILE *p = 0;
2082 char *s;
2084 to = name_quote (to, 0);
2085 subject = name_quote (subject, 0);
2086 cc = name_quote (cc, 0);
2087 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2088 g_free (to);
2089 g_free (subject);
2090 g_free (cc);
2092 if (s) {
2093 p = popen (s, "w");
2094 g_free (s);
2097 if (p) {
2098 long i;
2099 for (i = 0; i < edit->last_byte; i++)
2100 fputc (edit_get_byte (edit, i), p);
2101 pclose (p);
2105 #define MAIL_DLG_HEIGHT 12
2107 void edit_mail_dialog (WEdit * edit)
2109 char *tmail_to;
2110 char *tmail_subject;
2111 char *tmail_cc;
2113 static char *mail_cc_last = 0;
2114 static char *mail_subject_last = 0;
2115 static char *mail_to_last = 0;
2117 QuickDialog Quick_input =
2118 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2119 "[Input Line Keys]", 0, 0};
2121 QuickWidget quick_widgets[] =
2123 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2124 0, NULL, NULL, NULL},
2125 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
2126 0, NULL, NULL, NULL},
2127 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2128 0, "mail-dlg-input", NULL, NULL},
2129 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2130 0, 0, NULL, NULL},
2131 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2132 0, "mail-dlg-input-2", NULL, NULL},
2133 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2134 0, 0, NULL, NULL},
2135 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2136 0, "mail-dlg-input-3", NULL, NULL},
2137 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2138 0, 0, NULL, NULL},
2139 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2140 0, 0, NULL, NULL},
2141 NULL_QuickWidget};
2143 quick_widgets[2].str_result = &tmail_cc;
2144 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2145 quick_widgets[4].str_result = &tmail_subject;
2146 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2147 quick_widgets[6].str_result = &tmail_to;
2148 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2150 Quick_input.widgets = quick_widgets;
2152 if (quick_dialog (&Quick_input) != B_CANCEL) {
2153 g_free (mail_cc_last);
2154 g_free (mail_subject_last);
2155 g_free (mail_to_last);
2156 mail_cc_last = tmail_cc;
2157 mail_subject_last = tmail_subject;
2158 mail_to_last = tmail_to;
2159 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2164 /*******************/
2165 /* Word Completion */
2166 /*******************/
2169 /* find first character of current word */
2170 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2172 int i, c, last;
2174 /* return if at begin of file */
2175 if (edit->curs1 <= 0)
2176 return 0;
2178 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2179 /* return if not at end or in word */
2180 if (isspace (c) || !(isalnum (c) || c == '_'))
2181 return 0;
2183 /* search start of word to be completed */
2184 for (i = 2;; i++) {
2185 /* return if at begin of file */
2186 if (edit->curs1 - i < 0)
2187 return 0;
2189 last = c;
2190 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2192 if (!(isalnum (c) || c == '_')) {
2193 /* return if word starts with digit */
2194 if (isdigit (last))
2195 return 0;
2197 *word_start = edit->curs1 - (i - 1); /* start found */
2198 *word_len = i - 1;
2199 break;
2202 /* success */
2203 return 1;
2207 /* (re)set search parameters to the given values */
2208 static void edit_set_search_parameters (WEdit *edit, int replace_mode, int rb, int rc)
2210 edit->replace_mode = replace_mode;
2211 edit->replace_backwards = rb;
2212 edit->replace_case = rc;
2216 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2218 /* collect the possible completions */
2219 static int
2220 edit_collect_completions (WEdit *edit, long start, int word_len,
2221 char *match_expr, struct selection *compl,
2222 int *num)
2224 int len = 0, max_len = 0, i, skip;
2225 unsigned char *bufpos;
2227 (void) match_expr;
2228 /* collect max MAX_WORD_COMPLETIONS completions */
2229 while (*num < MAX_WORD_COMPLETIONS) {
2230 /* get next match */
2232 start =
2233 edit_find (start - 1, (unsigned char *) match_expr, &len,
2234 edit->last_byte, edit_get_byte_ptr, (void *) edit, 0);
2236 start = -1;
2237 /* not matched */
2238 if (start < 0)
2239 break;
2241 /* add matched completion if not yet added */
2242 bufpos =
2243 &edit->
2244 buffers1[start >> S_EDIT_BUF_SIZE][start & M_EDIT_BUF_SIZE];
2245 skip = 0;
2246 for (i = 0; i < *num; i++) {
2247 if (strncmp
2248 ((char *) &compl[i].text[word_len],
2249 (char *) &bufpos[word_len], max (len,
2250 compl[i].len) -
2251 word_len) == 0) {
2252 skip = 1;
2253 break; /* skip it, already added */
2256 if (skip)
2257 continue;
2259 compl[*num].text = g_malloc (len + 1);
2260 compl[*num].len = len;
2261 for (i = 0; i < len; i++)
2262 compl[*num].text[i] = *(bufpos + i);
2263 compl[*num].text[i] = '\0';
2264 (*num)++;
2266 /* note the maximal length needed for the completion dialog */
2267 if (len > max_len)
2268 max_len = len;
2270 return max_len;
2274 * Complete current word using regular expression search
2275 * backwards beginning at the current cursor position.
2277 void
2278 edit_complete_word_cmd (WEdit *edit)
2280 int word_len = 0, i, num_compl = 0, max_len;
2281 long word_start = 0;
2282 unsigned char *bufpos;
2283 char *match_expr;
2284 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2286 /* don't want to disturb another search */
2287 int old_replace_mode = edit->replace_mode;
2288 int old_rb = edit->replace_backwards;
2289 int old_rc = edit->replace_case;
2291 /* search start of word to be completed */
2292 if (!edit_find_word_start (edit, &word_start, &word_len))
2293 return;
2295 /* prepare match expression */
2296 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2297 [word_start & M_EDIT_BUF_SIZE];
2299 match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos);
2300 /* init search: backward, regexp, whole word, case sensitive */
2301 edit_set_search_parameters (edit, 0, 1, 1);
2303 /* collect the possible completions */
2304 /* start search from curs1 down to begin of file */
2305 max_len =
2306 edit_collect_completions (edit, word_start, word_len, match_expr,
2307 (struct selection *) &compl, &num_compl);
2309 if (num_compl > 0) {
2310 /* insert completed word if there is only one match */
2311 if (num_compl == 1) {
2312 for (i = word_len; i < compl[0].len; i++)
2313 edit_insert (edit, *(compl[0].text + i));
2315 /* more than one possible completion => ask the user */
2316 else {
2317 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2318 /* !!! pressed again the selection dialog pops up, but that !!! */
2319 /* !!! seems to require a further internal state !!! */
2320 /*beep (); */
2322 /* let the user select the preferred completion */
2323 editcmd_dialog_completion_show (edit, max_len, word_len,
2324 (struct selection *) &compl,
2325 num_compl);
2329 g_free (match_expr);
2330 /* release memory before return */
2331 for (i = 0; i < num_compl; i++)
2332 g_free (compl[i].text);
2334 /* restore search parameters */
2335 edit_set_search_parameters (edit, old_replace_mode, old_rb, old_rc);
2338 void
2339 edit_select_codepage_cmd (WEdit *edit)
2341 #ifdef HAVE_CHARSET
2342 if (do_select_codepage ()) {
2343 const char *cp_id;
2345 cp_id = get_codepage_id (source_codepage >= 0 ?
2346 source_codepage : display_codepage);
2348 if (cp_id != NULL)
2349 edit->utf8 = str_isutf8 (cp_id);
2352 edit->force = REDRAW_COMPLETELY;
2353 edit_refresh_cmd (edit);
2354 #endif
2357 void
2358 edit_insert_literal_cmd (WEdit *edit)
2360 int char_for_insertion =
2361 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2362 _(" Press any key: "), 0);
2363 edit_execute_key_command (edit, -1,
2364 ascii_alpha_to_cntrl (char_for_insertion));
2367 void
2368 edit_execute_macro_cmd (WEdit *edit)
2370 int command =
2371 CK_Macro (editcmd_dialog_raw_key_query
2372 (_(" Execute Macro "), _(" Press macro hotkey: "),
2373 1));
2374 if (command == CK_Macro (0))
2375 command = CK_Insert_Char;
2377 edit_execute_key_command (edit, command, -1);
2380 void
2381 edit_begin_end_macro_cmd(WEdit *edit)
2383 int command;
2385 /* edit is a pointer to the widget */
2386 if (edit) {
2387 command =
2388 edit->macro_i <
2389 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2390 edit_execute_key_command (edit, command, -1);
2395 edit_load_forward_cmd (WEdit *edit)
2397 if (edit->modified) {
2398 if (edit_query_dialog2
2399 (_("Warning"),
2400 _(" Current text was modified without a file save. \n"
2401 " Continue discards these changes. "), _("C&ontinue"),
2402 _("&Cancel"))) {
2403 edit->force |= REDRAW_COMPLETELY;
2404 return 0;
2407 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2408 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2409 return 1;
2411 edit_stack_iterator++;
2412 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2413 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2414 edit_history_moveto[edit_stack_iterator].line);
2415 return 0;
2416 } else {
2417 return 1;
2419 } else {
2420 return 1;
2425 edit_load_back_cmd (WEdit *edit)
2427 if (edit->modified) {
2428 if (edit_query_dialog2
2429 (_("Warning"),
2430 _(" Current text was modified without a file save. \n"
2431 " Continue discards these changes. "), _("C&ontinue"),
2432 _("&Cancel"))) {
2433 edit->force |= REDRAW_COMPLETELY;
2434 return 0;
2437 if ( edit_stack_iterator > 0 ) {
2438 edit_stack_iterator--;
2439 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2440 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2441 edit_history_moveto[edit_stack_iterator].line);
2442 return 0;
2443 } else {
2444 return 1;
2446 } else {
2447 return 1;
2451 void
2452 edit_get_match_keyword_cmd (WEdit *edit)
2454 int word_len = 0;
2455 int num_def = 0;
2456 int max_len = 0;
2457 int i;
2458 long word_start = 0;
2459 unsigned char *bufpos;
2460 char *match_expr;
2461 char *path = NULL;
2462 char *ptr = NULL;
2463 char *tagfile = NULL;
2465 etags_hash_t def_hash[MAX_DEFINITIONS];
2467 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2468 def_hash[i].filename = NULL;
2471 /* search start of word to be completed */
2472 if (!edit_find_word_start (edit, &word_start, &word_len))
2473 return;
2475 /* prepare match expression */
2476 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2477 [word_start & M_EDIT_BUF_SIZE];
2478 match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
2480 ptr = g_get_current_dir ();
2481 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2482 g_free (ptr);
2484 /* Recursive search file 'TAGS' in parent dirs */
2485 do {
2486 ptr = g_path_get_dirname (path);
2487 g_free(path); path = ptr;
2488 g_free (tagfile);
2489 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2490 if ( exist_file (tagfile) )
2491 break;
2492 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2494 if (tagfile){
2495 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2496 g_free (tagfile);
2498 g_free (path);
2500 max_len = MAX_WIDTH_DEF_DIALOG;
2501 word_len = 0;
2502 if ( num_def > 0 ) {
2503 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2504 (etags_hash_t *) &def_hash,
2505 num_def);
2507 g_free (match_expr);
2510 void
2511 edit_move_block_to_right (WEdit * edit)
2513 long start_mark, end_mark;
2514 long cur_bol, start_bol;
2516 if ( eval_marks (edit, &start_mark, &end_mark) )
2517 return;
2519 start_bol = edit_bol (edit, start_mark);
2520 cur_bol = edit_bol (edit, end_mark - 1);
2521 do {
2522 edit_cursor_move (edit, cur_bol - edit->curs1);
2523 if ( option_fill_tabs_with_spaces ) {
2524 if ( option_fake_half_tabs ) {
2525 insert_spaces_tab (edit, 1);
2526 } else {
2527 insert_spaces_tab (edit, 0);
2529 } else {
2530 edit_insert (edit, '\t');
2532 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2533 if ( cur_bol == 0 ) {
2534 break;
2536 cur_bol = edit_bol (edit, cur_bol - 1);
2537 } while (cur_bol >= start_bol) ;
2538 edit->force |= REDRAW_PAGE;
2541 void
2542 edit_move_block_to_left (WEdit * edit)
2544 long start_mark, end_mark;
2545 long cur_bol, start_bol;
2546 int i, del_tab_width;
2547 int next_char;
2549 if ( eval_marks (edit, &start_mark, &end_mark) )
2550 return;
2552 start_bol = edit_bol (edit, start_mark);
2553 cur_bol = edit_bol (edit, end_mark - 1);
2554 do {
2555 edit_cursor_move (edit, cur_bol - edit->curs1);
2556 if (option_fake_half_tabs) {
2557 del_tab_width = HALF_TAB_SIZE;
2558 } else {
2559 del_tab_width = option_tab_spacing;
2561 next_char = edit_get_byte (edit, edit->curs1);
2562 if ( next_char == '\t' ) {
2563 edit_delete (edit, 1);
2564 } else if ( next_char == ' ' ) {
2565 for (i = 1; i <= del_tab_width; i++) {
2566 if ( next_char == ' ' ) {
2567 edit_delete (edit, 1);
2569 next_char = edit_get_byte (edit, edit->curs1);
2572 if ( cur_bol == 0 ) {
2573 break;
2575 cur_bol = edit_bol (edit, cur_bol - 1);
2576 } while (cur_bol >= start_bol) ;
2577 edit->force |= REDRAW_PAGE;