view.c: made compilable.
[midnight-commander.git] / edit / editcmd.c
blob82f68eaeacbb19774a235c6d5c8ff36228176a83
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 {
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;
340 if (filelen != edit->last_byte)
341 goto error_save;
343 if (this_save_mode == EDIT_DO_BACKUP) {
344 assert (option_backup_ext != NULL);
345 tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
346 if (mc_rename (real_filename, tmp) == -1){
347 g_free(tmp);
348 goto error_save;
352 if (this_save_mode != EDIT_QUICK_SAVE)
353 if (mc_rename (savename, real_filename) == -1)
354 goto error_save;
355 g_free (savename);
356 g_free(real_filename);
357 return 1;
358 error_save:
359 /* FIXME: Is this safe ?
360 * if (this_save_mode != EDIT_QUICK_SAVE)
361 * mc_unlink (savename);
363 g_free(real_filename);
364 g_free (savename);
365 return 0;
368 void menu_save_mode_cmd (void)
370 #define DLG_X 38
371 #define DLG_Y 10
372 static char *str_result;
373 static int save_mode_new;
374 static const char *str[] =
376 N_("Quick save "),
377 N_("Safe save "),
378 N_("Do backups -->")};
380 static QuickWidget widgets[] =
382 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
383 B_CANCEL, 0, 0, NULL, NULL, NULL},
384 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
385 B_ENTER, 0, 0, NULL, NULL, NULL},
386 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
387 0, 0, &str_result, "edit-backup-ext", NULL, NULL},
388 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
389 0, 0, 0, NULL, NULL, NULL},
390 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
391 0, &save_mode_new, (char **) str, NULL, NULL, NULL},
392 NULL_QuickWidget};
393 static QuickDialog dialog =
394 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
395 widgets, 0};
396 static int i18n_flag = 0;
398 if (!i18n_flag) {
399 size_t i;
400 size_t maxlen = 0;
401 int dlg_x;
402 size_t l1;
404 /* OK/Cancel buttons */
405 l1 = str_term_width1 (_(widgets[0].text)) + str_term_width1 (_(widgets[1].text)) + 5;
406 maxlen = max (maxlen, l1);
408 for (i = 0; i < 3; i++ ) {
409 str[i] = _(str[i]);
410 maxlen = max (maxlen, (size_t) str_term_width1 (str[i]) + 7);
412 i18n_flag = 1;
414 dlg_x = maxlen + str_term_width1 (_(widgets[3].text)) + 5 + 1;
415 widgets[2].hotkey_pos = str_term_width1 (_(widgets[3].text)); /* input field length */
416 dlg_x = min (COLS, dlg_x);
417 dialog.xlen = dlg_x;
419 i = (dlg_x - l1)/3;
420 widgets[1].relative_x = i;
421 widgets[0].relative_x = i + str_term_width1 (_(widgets[1].text)) + i + 4;
423 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
425 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
426 widgets[i].x_divisions = dlg_x;
429 assert (option_backup_ext != NULL);
430 widgets[2].text = option_backup_ext;
431 widgets[4].value = option_save_mode;
432 if (quick_dialog (&dialog) != B_ENTER)
433 return;
434 option_save_mode = save_mode_new;
436 g_free (option_backup_ext);
437 option_backup_ext = str_result;
438 str_result = NULL;
441 void
442 edit_set_filename (WEdit *edit, const char *f)
444 g_free (edit->filename);
445 if (!f)
446 f = "";
447 edit->filename = g_strdup (f);
448 if (edit->dir == NULL && *f != PATH_SEP)
449 #ifdef USE_VFS
450 edit->dir = g_strdup (vfs_get_current_dir ());
451 #else
452 edit->dir = g_get_current_dir ();
453 #endif
456 /* Here we want to warn the users of overwriting an existing file,
457 but only if they have made a change to the filename */
458 /* returns 1 on success */
460 edit_save_as_cmd (WEdit *edit)
462 /* This heads the 'Save As' dialog box */
463 char *exp;
464 int save_lock = 0;
465 int different_filename = 0;
467 exp = input_expand_dialog (
468 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS, edit->filename);
469 edit_push_action (edit, KEY_PRESS + edit->start_display);
471 if (exp) {
472 if (!*exp) {
473 g_free (exp);
474 edit->force |= REDRAW_COMPLETELY;
475 return 0;
476 } else {
477 int rv;
478 if (strcmp (edit->filename, exp)) {
479 int file;
480 different_filename = 1;
481 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
482 /* the file exists */
483 mc_close (file);
484 /* Overwrite the current file or cancel the operation */
485 if (edit_query_dialog2
486 (_("Warning"),
487 _(" A file already exists with this name. "),
488 _("&Overwrite"), _("&Cancel"))) {
489 edit->force |= REDRAW_COMPLETELY;
490 g_free (exp);
491 return 0;
493 } else {
494 edit->stat1.st_mode |= S_IWUSR;
496 save_lock = edit_lock_file (exp);
497 } else {
498 /* filenames equal, check if already locked */
499 if (!edit->locked && !edit->delete_file)
500 save_lock = edit_lock_file (exp);
503 if (different_filename)
506 * Allow user to write into saved (under another name) file
507 * even if original file had r/o user permissions.
509 edit->stat1.st_mode |= S_IWRITE;
512 rv = edit_save_file (edit, exp);
513 switch (rv) {
514 case 1:
515 /* Succesful, so unlock both files */
516 if (different_filename) {
517 if (save_lock)
518 edit_unlock_file (exp);
519 if (edit->locked)
520 edit->locked = edit_unlock_file (edit->filename);
521 } else {
522 if (edit->locked || save_lock)
523 edit->locked = edit_unlock_file (edit->filename);
526 edit_set_filename (edit, exp);
527 g_free (exp);
528 edit->modified = 0;
529 edit->delete_file = 0;
530 if (different_filename)
531 edit_load_syntax (edit, NULL, option_syntax_type);
532 edit->force |= REDRAW_COMPLETELY;
533 return 1;
534 default:
535 edit_error_dialog (_(" Save As "),
536 get_sys_error (_
537 (" Cannot save file. ")));
538 /* fallthrough */
539 case -1:
540 /* Failed, so maintain modify (not save) lock */
541 if (save_lock)
542 edit_unlock_file (exp);
543 g_free (exp);
544 edit->force |= REDRAW_COMPLETELY;
545 return 0;
549 edit->force |= REDRAW_COMPLETELY;
550 return 0;
553 /* {{{ Macro stuff starts here */
555 /* creates a macro file if it doesn't exist */
556 static FILE *edit_open_macro_file (const char *r)
558 gchar *filename;
559 FILE *fd;
560 int file;
561 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
562 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
563 g_free(filename);
564 return 0;
566 close (file);
567 fd = fopen (filename, r);
568 g_free(filename);
569 return fd;
572 #define MAX_MACROS 1024
573 static int saved_macro[MAX_MACROS + 1];
574 static int saved_macros_loaded = 0;
577 This is just to stop the macro file be loaded over and over for keys
578 that aren't defined to anything. On slow systems this could be annoying.
580 static int
581 macro_exists (int k)
583 int i;
584 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
585 if (saved_macro[i] == k)
586 return i;
587 return -1;
590 /* returns 1 on error */
591 static int
592 edit_delete_macro (WEdit * edit, int k)
594 gchar *tmp, *tmp2;
595 struct macro macro[MAX_MACRO_LENGTH];
596 FILE *f, *g;
597 int s, i, n, j = 0;
599 (void) edit;
601 if (saved_macros_loaded)
602 if ((j = macro_exists (k)) < 0)
603 return 0;
604 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
605 g = fopen (tmp , "w");
606 g_free(tmp);
607 if (!g) {
608 edit_error_dialog (_(" Delete macro "),
609 get_sys_error (_(" Cannot open temp file ")));
610 return 1;
612 f = edit_open_macro_file ("r");
613 if (!f) {
614 edit_error_dialog (_(" Delete macro "),
615 get_sys_error (_(" Cannot open macro file ")));
616 fclose (g);
617 return 1;
619 for (;;) {
620 n = fscanf (f, ("key '%d 0': "), &s);
621 if (!n || n == EOF)
622 break;
623 n = 0;
624 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
625 n++;
626 fscanf (f, ";\n");
627 if (s != k) {
628 fprintf (g, ("key '%d 0': "), s);
629 for (i = 0; i < n; i++)
630 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
631 fprintf (g, ";\n");
634 fclose (f);
635 fclose (g);
636 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
637 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
638 if (rename ( tmp, tmp2) == -1) {
639 edit_error_dialog (_(" Delete macro "),
640 get_sys_error (_(" Cannot overwrite macro file ")));
641 g_free(tmp);
642 g_free(tmp2);
643 return 1;
645 g_free(tmp);
646 g_free(tmp2);
648 if (saved_macros_loaded)
649 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
650 return 0;
653 /* returns 0 on error */
654 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
656 FILE *f;
657 int s, i;
659 edit_push_action (edit, KEY_PRESS + edit->start_display);
660 s = editcmd_dialog_raw_key_query (_(" Save macro "),
661 _(" Press the macro's new hotkey: "), 1);
662 edit->force |= REDRAW_COMPLETELY;
663 if (s) {
664 if (edit_delete_macro (edit, s))
665 return 0;
666 f = edit_open_macro_file ("a+");
667 if (f) {
668 fprintf (f, ("key '%d 0': "), s);
669 for (i = 0; i < n; i++)
670 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
671 fprintf (f, ";\n");
672 fclose (f);
673 if (saved_macros_loaded) {
674 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
675 saved_macro[i] = s;
677 return 1;
678 } else
679 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
681 return 0;
684 void edit_delete_macro_cmd (WEdit * edit)
686 int command;
688 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
689 _ (" Press macro hotkey: "), 1);
691 if (!command)
692 return;
694 edit_delete_macro (edit, command);
697 /* return 0 on error */
698 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
700 FILE *f;
701 int s, i = 0, found = 0;
703 (void) edit;
705 if (saved_macros_loaded)
706 if (macro_exists (k) < 0)
707 return 0;
709 if ((f = edit_open_macro_file ("r"))) {
710 struct macro dummy;
711 do {
712 int u;
713 u = fscanf (f, ("key '%d 0': "), &s);
714 if (!u || u == EOF)
715 break;
716 if (!saved_macros_loaded)
717 saved_macro[i++] = s;
718 if (!found) {
719 *n = 0;
720 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
721 (*n)++;
722 } else {
723 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
725 fscanf (f, ";\n");
726 if (s == k)
727 found = 1;
728 } while (!found || !saved_macros_loaded);
729 if (!saved_macros_loaded) {
730 saved_macro[i] = 0;
731 saved_macros_loaded = 1;
733 fclose (f);
734 return found;
735 } else
736 edit_error_dialog (_(" Load macro "),
737 get_sys_error (_(" Cannot open macro file ")));
738 return 0;
741 /* }}} Macro stuff starts here */
743 /* returns 1 on success */
744 int edit_save_confirm_cmd (WEdit * edit)
746 gchar *f = NULL;
748 if (edit_confirm_save) {
749 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
750 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
751 g_free(f);
752 return 0;
754 g_free(f);
756 return edit_save_cmd (edit);
760 /* returns 1 on success */
761 static int
762 edit_save_cmd (WEdit *edit)
764 int res, save_lock = 0;
766 if (!edit->locked && !edit->delete_file)
767 save_lock = edit_lock_file (edit->filename);
768 res = edit_save_file (edit, edit->filename);
770 /* Maintain modify (not save) lock on failure */
771 if ((res > 0 && edit->locked) || save_lock)
772 edit->locked = edit_unlock_file (edit->filename);
774 /* On failure try 'save as', it does locking on its own */
775 if (!res)
776 return edit_save_as_cmd (edit);
777 edit->force |= REDRAW_COMPLETELY;
778 if (res > 0) {
779 edit->delete_file = 0;
780 edit->modified = 0;
783 return 1;
787 /* returns 1 on success */
788 int edit_new_cmd (WEdit * edit)
790 if (edit->modified) {
791 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
792 edit->force |= REDRAW_COMPLETELY;
793 return 0;
796 edit->force |= REDRAW_COMPLETELY;
798 return edit_renew (edit); /* if this gives an error, something has really screwed up */
801 /* returns 1 on error */
802 static int
803 edit_load_file_from_filename (WEdit * edit, char *exp)
805 int prev_locked = edit->locked;
806 char *prev_filename = g_strdup (edit->filename);
808 if (!edit_reload (edit, exp)) {
809 g_free (prev_filename);
810 return 1;
813 if (prev_locked)
814 edit_unlock_file (prev_filename);
815 g_free (prev_filename);
816 return 0;
819 static void
820 edit_load_syntax_file (WEdit * edit)
822 char *extdir;
823 int dir = 0;
825 if (geteuid () == 0) {
826 dir = query_dialog (_("Syntax file edit"),
827 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
828 _("&User"), _("&System Wide"));
831 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
832 if (!exist_file(extdir)) {
833 g_free (extdir);
834 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
837 if (dir == 0) {
838 char *buffer;
840 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
841 check_for_default (extdir, buffer);
842 edit_load_file_from_filename (edit, buffer);
843 g_free (buffer);
844 } else if (dir == 1)
845 edit_load_file_from_filename (edit, extdir);
847 g_free (extdir);
850 static void
851 edit_load_menu_file (WEdit * edit)
853 char *buffer;
854 char *menufile;
855 int dir = 0;
857 dir = query_dialog (
858 _(" Menu edit "),
859 _(" Which menu file do you want to edit? "), D_NORMAL,
860 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
863 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
865 if (!exist_file (menufile)) {
866 g_free (menufile);
867 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
870 switch (dir) {
871 case 0:
872 buffer = g_strdup (EDIT_LOCAL_MENU);
873 check_for_default (menufile, buffer);
874 chmod (buffer, 0600);
875 break;
877 case 1:
878 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
879 check_for_default (menufile, buffer);
880 break;
882 case 2:
883 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
884 if (!exist_file (buffer)) {
885 g_free (buffer);
886 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
888 break;
890 default:
891 g_free (menufile);
892 return;
895 edit_load_file_from_filename (edit, buffer);
897 g_free (buffer);
898 g_free (menufile);
902 edit_load_cmd (WEdit *edit, edit_current_file_t what)
904 char *exp;
906 if (edit->modified
907 && (edit_query_dialog2
908 (_("Warning"),
909 _(" Current text was modified without a file save. \n"
910 " Continue discards these changes. "),
911 _("C&ontinue"), _("&Cancel")) == 1)) {
912 edit->force |= REDRAW_COMPLETELY;
913 return 0;
916 switch (what) {
917 case EDIT_FILE_COMMON:
918 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
919 MC_HISTORY_EDIT_LOAD, edit->filename);
921 if (exp) {
922 if (*exp)
923 edit_load_file_from_filename (edit, exp);
924 g_free (exp);
926 break;
928 case EDIT_FILE_SYNTAX:
929 edit_load_syntax_file (edit);
930 break;
932 case EDIT_FILE_MENU:
933 edit_load_menu_file (edit);
934 break;
936 default:
937 break;
940 edit->force |= REDRAW_COMPLETELY;
941 return 0;
945 if mark2 is -1 then marking is from mark1 to the cursor.
946 Otherwise its between the markers. This handles this.
947 Returns 1 if no text is marked.
949 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
951 if (edit->mark1 != edit->mark2) {
952 if (edit->mark2 >= 0) {
953 *start_mark = min (edit->mark1, edit->mark2);
954 *end_mark = max (edit->mark1, edit->mark2);
955 } else {
956 *start_mark = min (edit->mark1, edit->curs1);
957 *end_mark = max (edit->mark1, edit->curs1);
958 edit->column2 = edit->curs_col + edit->over_col;
960 return 0;
961 } else {
962 *start_mark = *end_mark = 0;
963 edit->column2 = edit->column1 = 0;
964 return 1;
968 #define space_width 1
970 void
971 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
973 long cursor;
974 int i, col;
975 cursor = edit->curs1;
976 col = edit_get_col (edit);
977 for (i = 0; i < size; i++) {
978 if (data[i] == '\n') { /* fill in and move to next line */
979 int l;
980 long p;
981 if (edit_get_byte (edit, edit->curs1) != '\n') {
982 l = width - (edit_get_col (edit) - col);
983 while (l > 0) {
984 edit_insert (edit, ' ');
985 l -= space_width;
988 for (p = edit->curs1;; p++) {
989 if (p == edit->last_byte) {
990 edit_cursor_move (edit, edit->last_byte - edit->curs1);
991 edit_insert_ahead (edit, '\n');
992 p++;
993 break;
995 if (edit_get_byte (edit, p) == '\n') {
996 p++;
997 break;
1000 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1001 l = col - edit_get_col (edit);
1002 while (l >= space_width) {
1003 edit_insert (edit, ' ');
1004 l -= space_width;
1006 continue;
1008 edit_insert (edit, data[i]);
1010 edit_cursor_move (edit, cursor - edit->curs1);
1013 #define TEMP_BUF_LEN 1024
1016 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1018 long cursor;
1019 int i, col;
1020 int blocklen = -1, width;
1021 unsigned char *data;
1022 cursor = edit->curs1;
1023 col = edit_get_col (edit);
1024 data = g_malloc (TEMP_BUF_LEN);
1025 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1026 for (width = 0; width < blocklen; width++) {
1027 if (data[width] == '\n')
1028 break;
1030 for (i = 0; i < blocklen; i++) {
1031 if (data[i] == '\n') { /* fill in and move to next line */
1032 int l;
1033 long p;
1034 if (edit_get_byte (edit, edit->curs1) != '\n') {
1035 l = width - (edit_get_col (edit) - col);
1036 while (l > 0) {
1037 edit_insert (edit, ' ');
1038 l -= space_width;
1041 for (p = edit->curs1;; p++) {
1042 if (p == edit->last_byte) {
1043 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1044 edit_insert_ahead (edit, '\n');
1045 p++;
1046 break;
1048 if (edit_get_byte (edit, p) == '\n') {
1049 p++;
1050 break;
1053 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1054 l = col - edit_get_col (edit);
1055 while (l >= space_width) {
1056 edit_insert (edit, ' ');
1057 l -= space_width;
1059 continue;
1061 edit_insert (edit, data[i]);
1064 edit_cursor_move (edit, cursor - edit->curs1);
1065 g_free(data);
1066 edit->force |= REDRAW_PAGE;
1067 return blocklen;
1070 void
1071 edit_block_copy_cmd (WEdit *edit)
1073 long start_mark, end_mark, current = edit->curs1;
1074 int size;
1075 unsigned char *copy_buf;
1077 edit_update_curs_col (edit);
1078 if (eval_marks (edit, &start_mark, &end_mark))
1079 return;
1081 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1083 /* all that gets pushed are deletes hence little space is used on the stack */
1085 edit_push_markers (edit);
1087 if (column_highlighting) {
1088 edit_insert_column_of_text (edit, copy_buf, size,
1089 abs (edit->column2 - edit->column1));
1090 } else {
1091 while (size--)
1092 edit_insert_ahead (edit, copy_buf[size]);
1095 g_free (copy_buf);
1096 edit_scroll_screen_over_cursor (edit);
1098 if (column_highlighting) {
1099 edit_set_markers (edit, 0, 0, 0, 0);
1100 edit_push_action (edit, COLUMN_ON);
1101 column_highlighting = 0;
1102 } else if (start_mark < current && end_mark > current)
1103 edit_set_markers (edit, start_mark,
1104 end_mark + end_mark - start_mark, 0, 0);
1106 edit->force |= REDRAW_PAGE;
1110 void
1111 edit_block_move_cmd (WEdit *edit)
1113 long count;
1114 long current;
1115 unsigned char *copy_buf;
1116 long start_mark, end_mark;
1117 int deleted = 0;
1118 int x = 0;
1120 if (eval_marks (edit, &start_mark, &end_mark))
1121 return;
1122 if (column_highlighting) {
1123 edit_update_curs_col (edit);
1124 x = edit->curs_col;
1125 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1126 if ((x > edit->column1 && x < edit->column2)
1127 || (x > edit->column2 && x < edit->column1))
1128 return;
1129 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1130 return;
1132 if ((end_mark - start_mark) > option_max_undo / 2)
1133 if (edit_query_dialog2
1134 (_("Warning"),
1136 (" Block is large, you may not be able to undo this action. "),
1137 _("C&ontinue"), _("&Cancel")))
1138 return;
1140 edit_push_markers (edit);
1141 current = edit->curs1;
1142 if (column_highlighting) {
1143 int size, c1, c2, line;
1144 line = edit->curs_line;
1145 if (edit->mark2 < 0)
1146 edit_mark_cmd (edit, 0);
1147 c1 = min (edit->column1, edit->column2);
1148 c2 = max (edit->column1, edit->column2);
1149 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1150 if (x < c2) {
1151 edit_block_delete_cmd (edit);
1152 deleted = 1;
1154 edit_move_to_line (edit, line);
1155 edit_cursor_move (edit,
1156 edit_move_forward3 (edit,
1157 edit_bol (edit, edit->curs1),
1158 x, 0) - edit->curs1);
1159 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1160 if (!deleted) {
1161 line = edit->curs_line;
1162 edit_update_curs_col (edit);
1163 x = edit->curs_col;
1164 edit_block_delete_cmd (edit);
1165 edit_move_to_line (edit, line);
1166 edit_cursor_move (edit,
1167 edit_move_forward3 (edit,
1168 edit_bol (edit,
1169 edit->curs1),
1170 x, 0) - edit->curs1);
1172 edit_set_markers (edit, 0, 0, 0, 0);
1173 edit_push_action (edit, COLUMN_ON);
1174 column_highlighting = 0;
1175 } else {
1176 copy_buf = g_malloc (end_mark - start_mark);
1177 edit_cursor_move (edit, start_mark - edit->curs1);
1178 edit_scroll_screen_over_cursor (edit);
1179 count = start_mark;
1180 while (count < end_mark) {
1181 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1182 count++;
1184 edit_scroll_screen_over_cursor (edit);
1185 edit_cursor_move (edit,
1186 current - edit->curs1 -
1187 (((current - edit->curs1) >
1188 0) ? end_mark - start_mark : 0));
1189 edit_scroll_screen_over_cursor (edit);
1190 while (count-- > start_mark)
1191 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1192 edit_set_markers (edit, edit->curs1,
1193 edit->curs1 + end_mark - start_mark, 0, 0);
1195 edit_scroll_screen_over_cursor (edit);
1196 g_free (copy_buf);
1197 edit->force |= REDRAW_PAGE;
1200 static void
1201 edit_delete_column_of_text (WEdit * edit)
1203 long p, q, r, m1, m2;
1204 int b, c, d;
1205 int n;
1207 eval_marks (edit, &m1, &m2);
1208 n = edit_move_forward (edit, m1, 0, m2) + 1;
1209 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1210 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1212 b = max(min (c, d), min (edit->column1, edit->column2));
1213 c = max (c, d + edit->over_col);
1215 while (n--) {
1216 r = edit_bol (edit, edit->curs1);
1217 p = edit_move_forward3 (edit, r, b, 0);
1218 q = edit_move_forward3 (edit, r, c, 0);
1219 if (p < m1)
1220 p = m1;
1221 if (q > m2)
1222 q = m2;
1223 edit_cursor_move (edit, p - edit->curs1);
1224 while (q > p) { /* delete line between margins */
1225 if (edit_get_byte (edit, edit->curs1) != '\n')
1226 edit_delete (edit, 1);
1227 q--;
1229 if (n) /* move to next line except on the last delete */
1230 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1234 /* if success return 0 */
1235 static int
1236 edit_block_delete (WEdit *edit)
1238 long count;
1239 long start_mark, end_mark;
1240 if (eval_marks (edit, &start_mark, &end_mark))
1241 return 0;
1242 if (column_highlighting && edit->mark2 < 0)
1243 edit_mark_cmd (edit, 0);
1244 if ((end_mark - start_mark) > option_max_undo / 2) {
1245 /* Warning message with a query to continue or cancel the operation */
1246 if (edit_query_dialog2
1247 (_("Warning"),
1249 (" Block is large, you may not be able to undo this action. "),
1250 _("C&ontinue"), _("&Cancel"))) {
1251 return 1;
1254 edit_push_markers (edit);
1255 edit_cursor_move (edit, start_mark - edit->curs1);
1256 edit_scroll_screen_over_cursor (edit);
1257 count = start_mark;
1258 if (start_mark < end_mark) {
1259 if (column_highlighting) {
1260 if (edit->mark2 < 0)
1261 edit_mark_cmd (edit, 0);
1262 edit_delete_column_of_text (edit);
1263 } else {
1264 while (count < end_mark) {
1265 edit_delete (edit, 1);
1266 count++;
1270 edit_set_markers (edit, 0, 0, 0, 0);
1271 edit->force |= REDRAW_PAGE;
1272 return 0;
1275 /* returns 1 if canceelled by user */
1276 int edit_block_delete_cmd (WEdit * edit)
1278 long start_mark, end_mark;
1279 if (eval_marks (edit, &start_mark, &end_mark)) {
1280 edit_delete_line (edit);
1281 return 0;
1283 return edit_block_delete (edit);
1286 #define INPUT_INDEX 9
1288 static gboolean
1289 editcmd_find (WEdit *edit, gsize *len)
1291 off_t search_start = edit->search_start;
1292 off_t search_end;
1293 long start_mark = 0;
1294 long end_mark = edit->last_byte;
1295 int mark_res = 0;
1297 if (edit->only_in_selection) {
1298 mark_res = eval_marks(edit, &start_mark, &end_mark);
1299 if (mark_res != 0) {
1300 edit->search->error = MC_SEARCH_E_NOTFOUND;
1301 edit->search->error_str = g_strdup(_(" Search string not found "));
1302 return FALSE;
1304 if (edit->replace_backwards) {
1305 if (search_start > end_mark || search_start <= start_mark) {
1306 search_start = end_mark;
1308 } else {
1309 if (search_start < start_mark || search_start >= end_mark) {
1310 search_start = start_mark;
1313 } else {
1314 if (edit->replace_backwards)
1315 end_mark = max(1, edit->curs1) - 1;
1317 if (edit->replace_backwards) {
1318 search_end = end_mark;
1319 while ((int) search_start >= start_mark) {
1320 if (search_end > search_start + edit->search->original_len
1321 && mc_search_is_fixed_search_str(edit->search)) {
1322 search_end = search_start + edit->search->original_len;
1324 if (mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1325 && edit->search->normal_offset == search_start ) {
1326 return TRUE;
1328 search_start--;
1330 edit->search->error_str = g_strdup(_(" Search string not found "));
1331 } else {
1332 return mc_search_run(edit->search, (void *) edit, search_start, end_mark, len);
1334 return FALSE;
1338 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1339 (and the above) routines to work properly - paul */
1341 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1343 static char *
1344 edit_replace_cmd__conv_to_display(char *str)
1346 #ifdef HAVE_CHARSET
1347 GString *tmp;
1348 tmp = str_convert_to_display (str);
1350 if (tmp && tmp->len){
1351 g_free(str);
1352 str = tmp->str;
1354 g_string_free (tmp, FALSE);
1355 return str;
1356 #else
1357 return g_strdup(str);
1358 #endif
1361 static char *
1362 edit_replace_cmd__conv_to_input(char *str)
1364 #ifdef HAVE_CHARSET
1365 GString *tmp;
1366 tmp = str_convert_to_input (str);
1368 if (tmp && tmp->len){
1369 g_free(str);
1370 str = tmp->str;
1372 g_string_free (tmp, FALSE);
1373 return str;
1374 #else
1375 return g_strdup(str);
1376 #endif
1378 /* call with edit = 0 before shutdown to close memory leaks */
1379 void
1380 edit_replace_cmd (WEdit *edit, int again)
1382 /* 1 = search string, 2 = replace with */
1383 static char *saved1 = NULL; /* saved default[123] */
1384 static char *saved2 = NULL;
1385 char *input1 = NULL; /* user input from the dialog */
1386 char *input2 = NULL;
1387 int replace_yes;
1388 long times_replaced = 0, last_search;
1389 gboolean once_found = FALSE;
1391 if (!edit) {
1392 g_free (saved1), saved1 = NULL;
1393 g_free (saved2), saved2 = NULL;
1394 return;
1397 last_search = edit->last_byte;
1399 edit->force |= REDRAW_COMPLETELY;
1401 if (again && !saved1 && !saved2)
1402 again = 0;
1404 if (again) {
1405 input1 = g_strdup (saved1 ? saved1 : "");
1406 input2 = g_strdup (saved2 ? saved2 : "");
1407 } else {
1408 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1409 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1411 edit_push_action (edit, KEY_PRESS + edit->start_display);
1413 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1415 g_free (disp1);
1416 g_free (disp2);
1418 if (input1 == NULL || *input1 == '\0') {
1419 edit->force = REDRAW_COMPLETELY;
1420 goto cleanup;
1423 input1 = edit_replace_cmd__conv_to_input(input1);
1424 input2 = edit_replace_cmd__conv_to_input(input2);
1426 g_free (saved1), saved1 = g_strdup (input1);
1427 g_free (saved2), saved2 = g_strdup (input2);
1429 if (edit->search) {
1430 mc_search_free(edit->search);
1431 edit->search = NULL;
1435 if (!edit->search) {
1436 edit->search = mc_search_new(input1, -1);
1437 if (edit->search == NULL) {
1438 edit->search_start = edit->curs1;
1439 return;
1441 edit->search->search_type = edit->search_type;
1442 edit->search->is_all_charsets = edit->all_codepages;
1443 edit->search->is_case_sentitive = edit->replace_case;
1444 edit->search->whole_words = edit->whole_words;
1445 edit->search->search_fn = edit_search_cmd_callback;
1448 if (edit->found_len && edit->search_start == edit->found_start + 1
1449 && edit->replace_backwards)
1450 edit->search_start--;
1452 if (edit->found_len && edit->search_start == edit->found_start - 1
1453 && !edit->replace_backwards)
1454 edit->search_start++;
1456 do {
1457 gsize len = 0;
1458 long new_start;
1460 if (! editcmd_find(edit, &len)) {
1461 if (!(edit->search->error == MC_SEARCH_E_OK ||
1462 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1463 edit_error_dialog (_ ("Search"), edit->search->error_str);
1465 break;
1467 once_found = TRUE;
1468 new_start = edit->search->normal_offset;
1470 edit->search_start = new_start = edit->search->normal_offset;
1471 /*returns negative on not found or error in pattern */
1473 if (edit->search_start >= 0) {
1474 guint i;
1476 edit->found_start = edit->search_start;
1477 i = edit->found_len = len;
1479 edit_cursor_move (edit, edit->search_start - edit->curs1);
1480 edit_scroll_screen_over_cursor (edit);
1482 replace_yes = 1;
1484 if (edit->replace_mode == 0) {
1485 int l;
1486 l = edit->curs_row - edit->num_widget_lines / 3;
1487 if (l > 0)
1488 edit_scroll_downward (edit, l);
1489 if (l < 0)
1490 edit_scroll_upward (edit, -l);
1492 edit_scroll_screen_over_cursor (edit);
1493 edit->force |= REDRAW_PAGE;
1494 edit_render_keypress (edit);
1496 /*so that undo stops at each query */
1497 edit_push_key_press (edit);
1498 /* and prompt 2/3 down */
1499 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1500 case B_ENTER:
1501 replace_yes = 1;
1502 break;
1503 case B_SKIP_REPLACE:
1504 replace_yes = 0;
1505 break;
1506 case B_REPLACE_ALL:
1507 edit->replace_mode=1;
1508 break;
1509 case B_CANCEL:
1510 replace_yes = 0;
1511 edit->replace_mode = -1;
1512 break;
1515 if (replace_yes) { /* delete then insert new */
1516 GString *repl_str, *tmp_str;
1517 tmp_str = g_string_new(input2);
1519 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1520 g_string_free(tmp_str, TRUE);
1521 if (edit->search->error != MC_SEARCH_E_OK)
1523 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1524 break;
1527 while (i--)
1528 edit_delete (edit, 1);
1530 while (++i < repl_str->len)
1531 edit_insert (edit, repl_str->str[i]);
1533 g_string_free(repl_str, TRUE);
1534 edit->found_len = i;
1536 /* so that we don't find the same string again */
1537 if (edit->replace_backwards) {
1538 last_search = edit->search_start;
1539 edit->search_start--;
1540 } else {
1541 edit->search_start += i;
1542 last_search = edit->last_byte;
1544 edit_scroll_screen_over_cursor (edit);
1545 } else {
1546 const char *msg = _(" Replace ");
1547 /* try and find from right here for next search */
1548 edit->search_start = edit->curs1;
1549 edit_update_curs_col (edit);
1551 edit->force |= REDRAW_PAGE;
1552 edit_render_keypress (edit);
1553 if (times_replaced) {
1554 message (D_NORMAL, msg, _(" %ld replacements made. "),
1555 times_replaced);
1556 } else
1557 query_dialog (msg, _(" Search string not found "),
1558 D_NORMAL, 1, _("&OK"));
1559 edit->replace_mode = -1;
1561 } while (edit->replace_mode >= 0);
1563 edit->force = REDRAW_COMPLETELY;
1564 edit_scroll_screen_over_cursor (edit);
1565 cleanup:
1566 g_free (input1);
1567 g_free (input2);
1571 void edit_search_cmd (WEdit * edit, int again)
1573 char *search_string = NULL, *search_string_dup = NULL;
1575 gsize len = 0;
1577 if (!edit)
1578 return;
1580 if (edit->search != NULL) {
1581 search_string = g_strndup(edit->search->original, edit->search->original_len);
1582 search_string_dup = search_string;
1583 } else {
1584 GList *history;
1585 history = history_get (MC_HISTORY_SHARED_SEARCH);
1586 if (history != NULL && history->data != NULL) {
1587 search_string_dup = search_string = (char *) g_strdup(history->data);
1588 history = g_list_first (history);
1589 g_list_foreach (history, (GFunc) g_free, NULL);
1590 g_list_free (history);
1592 edit->search_start = edit->curs1;
1595 if (!again) {
1596 #ifdef HAVE_CHARSET
1597 GString *tmp;
1598 if (search_string && *search_string) {
1599 tmp = str_convert_to_display (search_string);
1601 g_free(search_string_dup);
1602 search_string_dup = NULL;
1604 if (tmp && tmp->len)
1605 search_string = search_string_dup = tmp->str;
1606 g_string_free (tmp, FALSE);
1608 #endif /* HAVE_CHARSET */
1609 editcmd_dialog_search_show (edit, &search_string);
1610 #ifdef HAVE_CHARSET
1611 if (search_string && *search_string) {
1612 tmp = str_convert_to_input (search_string);
1613 if (tmp && tmp->len)
1614 search_string = tmp->str;
1616 g_string_free (tmp, FALSE);
1618 if (search_string_dup)
1619 g_free(search_string_dup);
1621 #endif /* HAVE_CHARSET */
1623 edit_push_action (edit, KEY_PRESS + edit->start_display);
1625 if (!search_string) {
1626 edit->force |= REDRAW_COMPLETELY;
1627 edit_scroll_screen_over_cursor (edit);
1628 return;
1631 if (edit->search) {
1632 mc_search_free(edit->search);
1633 edit->search = NULL;
1637 if (!edit->search) {
1638 edit->search = mc_search_new(search_string, -1);
1639 if (edit->search == NULL) {
1640 edit->search_start = edit->curs1;
1641 return;
1643 edit->search->search_type = edit->search_type;
1644 edit->search->is_all_charsets = edit->all_codepages;
1645 edit->search->is_case_sentitive = edit->replace_case;
1646 edit->search->whole_words = edit->whole_words;
1647 edit->search->search_fn = edit_search_cmd_callback;
1650 if (search_create_bookmark) {
1651 edit_search_cmd_search_create_bookmark(edit);
1652 } else {
1653 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1654 edit->search_start--;
1656 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1657 edit->search_start++;
1660 if (editcmd_find(edit, &len)) {
1661 edit->found_start = edit->search_start = edit->search->normal_offset;
1662 edit->found_len = len;
1663 edit->over_col = 0;
1664 edit_cursor_move (edit, edit->search_start - edit->curs1);
1665 edit_scroll_screen_over_cursor (edit);
1666 if (edit->replace_backwards)
1667 edit->search_start--;
1668 else
1669 edit->search_start++;
1670 } else {
1671 edit->search_start = edit->curs1;
1672 if (edit->search->error_str)
1673 edit_error_dialog (_ ("Search"), edit->search->error_str);
1677 edit->force |= REDRAW_COMPLETELY;
1678 edit_scroll_screen_over_cursor (edit);
1683 * Check if it's OK to close the editor. If there are unsaved changes,
1684 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1687 edit_ok_to_exit (WEdit *edit)
1689 if (!edit->modified)
1690 return 1;
1692 switch (edit_query_dialog3
1693 (_("Quit"), _(" File was modified, Save with exit? "),
1694 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1695 case 1:
1696 edit_push_markers (edit);
1697 edit_set_markers (edit, 0, 0, 0, 0);
1698 if (!edit_save_cmd (edit))
1699 return 0;
1700 break;
1701 case 2:
1702 break;
1703 case 0:
1704 case -1:
1705 return 0;
1708 return 1;
1711 /* Return a null terminated length of text. Result must be g_free'd */
1712 static unsigned char *
1713 edit_get_block (WEdit *edit, long start, long finish, int *l)
1715 unsigned char *s, *r;
1716 r = s = g_malloc (finish - start + 1);
1717 if (column_highlighting) {
1718 *l = 0;
1719 /* copy from buffer, excluding chars that are out of the column 'margins' */
1720 while (start < finish) {
1721 int c, x;
1722 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1723 start);
1724 c = edit_get_byte (edit, start);
1725 if ((x >= edit->column1 && x < edit->column2)
1726 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1727 *s++ = c;
1728 (*l)++;
1730 start++;
1732 } else {
1733 *l = finish - start;
1734 while (start < finish)
1735 *s++ = edit_get_byte (edit, start++);
1737 *s = 0;
1738 return r;
1741 /* save block, returns 1 on success */
1743 edit_save_block (WEdit * edit, const char *filename, long start,
1744 long finish)
1746 int len, file;
1748 if ((file =
1749 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1750 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1751 return 0;
1753 if (column_highlighting) {
1754 int r;
1755 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1756 if (r > 0) {
1757 unsigned char *block, *p;
1758 p = block = edit_get_block (edit, start, finish, &len);
1759 while (len) {
1760 r = mc_write (file, p, len);
1761 if (r < 0)
1762 break;
1763 p += r;
1764 len -= r;
1766 g_free (block);
1768 } else {
1769 unsigned char *buf;
1770 int i = start, end;
1771 len = finish - start;
1772 buf = g_malloc (TEMP_BUF_LEN);
1773 while (start != finish) {
1774 end = min (finish, start + TEMP_BUF_LEN);
1775 for (; i < end; i++)
1776 buf[i - start] = edit_get_byte (edit, i);
1777 len -= mc_write (file, (char *) buf, end - start);
1778 start = end;
1780 g_free (buf);
1782 mc_close (file);
1783 if (len)
1784 return 0;
1785 return 1;
1788 /* copies a block to clipboard file */
1789 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1791 int ret;
1792 gchar *tmp;
1793 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1794 ret = edit_save_block (edit, tmp, start, finish);
1795 g_free(tmp);
1796 return ret;
1800 void edit_paste_from_history (WEdit *edit)
1802 (void) edit;
1803 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1806 int edit_copy_to_X_buf_cmd (WEdit * edit)
1808 long start_mark, end_mark;
1809 if (eval_marks (edit, &start_mark, &end_mark))
1810 return 0;
1811 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1812 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1813 return 1;
1815 edit_mark_cmd (edit, 1);
1816 return 0;
1819 int edit_cut_to_X_buf_cmd (WEdit * edit)
1821 long start_mark, end_mark;
1822 if (eval_marks (edit, &start_mark, &end_mark))
1823 return 0;
1824 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1825 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1826 return 1;
1828 edit_block_delete_cmd (edit);
1829 edit_mark_cmd (edit, 1);
1830 return 0;
1833 void edit_paste_from_X_buf_cmd (WEdit * edit)
1835 gchar *tmp;
1836 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1837 edit_insert_file (edit, tmp);
1838 g_free(tmp);
1843 * Ask user for the line and go to that line.
1844 * Negative numbers mean line from the end (i.e. -1 is the last line).
1846 void
1847 edit_goto_cmd (WEdit *edit)
1849 char *f;
1850 static long line = 0; /* line as typed, saved as default */
1851 long l;
1852 char *error;
1853 char s[32];
1855 g_snprintf (s, sizeof (s), "%ld", line);
1856 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1857 line ? s : "");
1858 if (!f)
1859 return;
1861 if (!*f) {
1862 g_free (f);
1863 return;
1866 l = strtol (f, &error, 0);
1867 if (*error) {
1868 g_free (f);
1869 return;
1872 line = l;
1873 if (l < 0)
1874 l = edit->total_lines + l + 2;
1875 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
1876 edit_move_to_line (edit, l - 1);
1877 edit->force |= REDRAW_COMPLETELY;
1878 g_free (f);
1882 /* Return 1 on success */
1884 edit_save_block_cmd (WEdit *edit)
1886 long start_mark, end_mark;
1887 char *exp, *tmp;
1889 if (eval_marks (edit, &start_mark, &end_mark))
1890 return 1;
1892 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1893 exp =
1894 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
1895 MC_HISTORY_EDIT_SAVE_BLOCK,
1896 tmp);
1897 g_free(tmp);
1898 edit_push_action (edit, KEY_PRESS + edit->start_display);
1899 if (exp) {
1900 if (!*exp) {
1901 g_free (exp);
1902 return 0;
1903 } else {
1904 if (edit_save_block (edit, exp, start_mark, end_mark)) {
1905 g_free (exp);
1906 edit->force |= REDRAW_COMPLETELY;
1907 return 1;
1908 } else {
1909 g_free (exp);
1910 edit_error_dialog (_(" Save Block "),
1911 get_sys_error (_
1912 (" Cannot save file. ")));
1916 edit->force |= REDRAW_COMPLETELY;
1917 return 0;
1921 /* returns 1 on success */
1923 edit_insert_file_cmd (WEdit *edit)
1925 gchar *tmp;
1926 char *exp;
1928 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1929 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
1930 MC_HISTORY_EDIT_INSERT_FILE,
1931 tmp);
1932 g_free(tmp);
1933 edit_push_action (edit, KEY_PRESS + edit->start_display);
1934 if (exp) {
1935 if (!*exp) {
1936 g_free (exp);
1937 return 0;
1938 } else {
1939 if (edit_insert_file (edit, exp)) {
1940 g_free (exp);
1941 edit->force |= REDRAW_COMPLETELY;
1942 return 1;
1943 } else {
1944 g_free (exp);
1945 edit_error_dialog (_(" Insert File "),
1946 get_sys_error (_
1947 (" Cannot insert file. ")));
1951 edit->force |= REDRAW_COMPLETELY;
1952 return 0;
1955 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
1956 int edit_sort_cmd (WEdit * edit)
1958 static char *old = 0;
1959 char *exp, *tmp;
1960 long start_mark, end_mark;
1961 int e;
1963 if (eval_marks (edit, &start_mark, &end_mark)) {
1964 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
1965 return 0;
1968 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
1969 edit_save_block (edit, tmp, start_mark, end_mark);
1970 g_free(tmp);
1972 exp = input_dialog (_(" Run Sort "),
1973 _(" Enter sort options (see manpage) separated by whitespace: "),
1974 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
1976 if (!exp)
1977 return 1;
1978 g_free (old);
1979 old = exp;
1980 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
1981 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
1982 e = system (tmp);
1983 g_free(tmp);
1984 if (e) {
1985 if (e == -1 || e == 127) {
1986 edit_error_dialog (_(" Sort "),
1987 get_sys_error (_(" Cannot execute sort command ")));
1988 } else {
1989 char q[8];
1990 sprintf (q, "%d ", e);
1991 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
1992 edit_error_dialog (_(" Sort "), tmp);
1993 g_free(tmp);
1995 return -1;
1998 edit->force |= REDRAW_COMPLETELY;
2000 if (edit_block_delete_cmd (edit))
2001 return 1;
2002 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2003 edit_insert_file (edit, tmp);
2004 g_free(tmp);
2005 return 0;
2009 * Ask user for a command, execute it and paste its output back to the
2010 * editor.
2013 edit_ext_cmd (WEdit *edit)
2015 char *exp, *tmp;
2016 int e;
2018 exp =
2019 input_dialog (_("Paste output of external command"),
2020 _("Enter shell command(s):"),
2021 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
2023 if (!exp)
2024 return 1;
2026 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
2027 e = system (tmp);
2028 g_free(tmp);
2029 g_free (exp);
2031 if (e) {
2032 edit_error_dialog (_("External command"),
2033 get_sys_error (_("Cannot execute command")));
2034 return -1;
2037 edit->force |= REDRAW_COMPLETELY;
2038 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2039 edit_insert_file (edit, tmp);
2040 g_free(tmp);
2041 return 0;
2044 /* if block is 1, a block must be highlighted and the shell command
2045 processes it. If block is 0 the shell command is a straight system
2046 command, that just produces some output which is to be inserted */
2047 void
2048 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2050 long start_mark, end_mark;
2051 char buf[BUFSIZ];
2052 FILE *script_home = NULL;
2053 FILE *script_src = NULL;
2054 FILE *block_file = NULL;
2055 gchar *o, *h, *b, *tmp;
2056 char *quoted_name = NULL;
2058 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2059 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2060 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2062 if (!(script_home = fopen (h, "r"))) {
2063 if (!(script_home = fopen (h, "w"))) {
2064 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2065 edit_error_dialog ("", get_sys_error (tmp));
2066 g_free(tmp);
2067 goto edit_block_process_cmd__EXIT;
2069 if (!(script_src = fopen (o, "r"))) {
2070 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2071 if (!(script_src = fopen (o, "r"))) {
2072 fclose (script_home);
2073 unlink (h);
2074 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2075 edit_error_dialog ("", get_sys_error (tmp));
2076 g_free(tmp);
2077 goto edit_block_process_cmd__EXIT;
2080 while (fgets (buf, sizeof (buf), script_src))
2081 fputs (buf, script_home);
2082 if (fclose (script_home)) {
2083 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2084 edit_error_dialog ("", get_sys_error (tmp));
2085 g_free(tmp);
2086 goto edit_block_process_cmd__EXIT;
2088 chmod (h, 0700);
2089 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2090 edit_error_dialog ("", get_sys_error (tmp));
2091 g_free(tmp);
2094 open_error_pipe ();
2096 if (block) { /* for marked block run indent formatter */
2097 if (eval_marks (edit, &start_mark, &end_mark)) {
2098 edit_error_dialog (_("Process block"),
2100 (" You must first highlight a block of text. "));
2101 goto edit_block_process_cmd__EXIT;
2103 edit_save_block (edit, b, start_mark, end_mark);
2104 quoted_name = name_quote (edit->filename, 0);
2106 * Run script.
2107 * Initial space is to avoid polluting bash history.
2108 * Arguments:
2109 * $1 - name of the edited file (to check its extension etc).
2110 * $2 - file containing the current block.
2111 * $3 - file where error messages should be put
2112 * (for compatibility with old scripts).
2114 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2115 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2116 system (tmp);
2117 g_free(tmp);
2118 } else {
2120 * No block selected, just execute the command for the file.
2121 * Arguments:
2122 * $1 - name of the edited file.
2124 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2125 quoted_name, (char *) NULL);
2126 system (tmp);
2127 g_free(tmp);
2129 g_free (quoted_name);
2130 close_error_pipe (D_NORMAL, NULL);
2132 edit_refresh_cmd (edit);
2133 edit->force |= REDRAW_COMPLETELY;
2135 /* insert result block */
2136 if (block) {
2137 if (edit_block_delete_cmd (edit))
2138 goto edit_block_process_cmd__EXIT;
2139 edit_insert_file (edit, b);
2140 if ((block_file = fopen (b, "w")))
2141 fclose (block_file);
2142 goto edit_block_process_cmd__EXIT;
2144 edit_block_process_cmd__EXIT:
2145 g_free(b);
2146 g_free(h);
2147 g_free(o);
2148 return;
2151 /* prints at the cursor */
2152 /* returns the number of chars printed */
2153 int edit_print_string (WEdit * e, const char *s)
2155 int i = 0;
2156 while (s[i])
2157 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2158 e->force |= REDRAW_COMPLETELY;
2159 edit_update_screen (e);
2160 return i;
2164 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2166 FILE *p = 0;
2167 char *s;
2169 to = name_quote (to, 0);
2170 subject = name_quote (subject, 0);
2171 cc = name_quote (cc, 0);
2172 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2173 g_free (to);
2174 g_free (subject);
2175 g_free (cc);
2177 if (s) {
2178 p = popen (s, "w");
2179 g_free (s);
2182 if (p) {
2183 long i;
2184 for (i = 0; i < edit->last_byte; i++)
2185 fputc (edit_get_byte (edit, i), p);
2186 pclose (p);
2190 #define MAIL_DLG_HEIGHT 12
2192 void edit_mail_dialog (WEdit * edit)
2194 char *tmail_to;
2195 char *tmail_subject;
2196 char *tmail_cc;
2198 static char *mail_cc_last = 0;
2199 static char *mail_subject_last = 0;
2200 static char *mail_to_last = 0;
2202 QuickDialog Quick_input =
2203 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2204 "[Input Line Keys]", 0, 0};
2206 QuickWidget quick_widgets[] =
2208 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2209 0, NULL, NULL, NULL},
2210 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
2211 0, NULL, NULL, NULL},
2212 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2213 0, "mail-dlg-input", NULL, NULL},
2214 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2215 0, 0, NULL, NULL},
2216 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2217 0, "mail-dlg-input-2", NULL, NULL},
2218 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2219 0, 0, NULL, NULL},
2220 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2221 0, "mail-dlg-input-3", NULL, NULL},
2222 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2223 0, 0, NULL, NULL},
2224 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2225 0, 0, NULL, NULL},
2226 NULL_QuickWidget};
2228 quick_widgets[2].str_result = &tmail_cc;
2229 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2230 quick_widgets[4].str_result = &tmail_subject;
2231 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2232 quick_widgets[6].str_result = &tmail_to;
2233 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2235 Quick_input.widgets = quick_widgets;
2237 if (quick_dialog (&Quick_input) != B_CANCEL) {
2238 g_free (mail_cc_last);
2239 g_free (mail_subject_last);
2240 g_free (mail_to_last);
2241 mail_cc_last = tmail_cc;
2242 mail_subject_last = tmail_subject;
2243 mail_to_last = tmail_to;
2244 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2249 /*******************/
2250 /* Word Completion */
2251 /*******************/
2253 static gboolean is_break_char(char c)
2255 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2258 /* find first character of current word */
2259 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2261 int i, c, last;
2263 /* return if at begin of file */
2264 if (edit->curs1 <= 0)
2265 return 0;
2267 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2268 /* return if not at end or in word */
2269 if (is_break_char(c))
2270 return 0;
2272 /* search start of word to be completed */
2273 for (i = 2;; i++) {
2274 /* return if at begin of file */
2275 if (edit->curs1 - i < 0)
2276 return 0;
2278 last = c;
2279 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2281 if (is_break_char(c)) {
2282 /* return if word starts with digit */
2283 if (isdigit (last))
2284 return 0;
2286 *word_start = edit->curs1 - (i - 1); /* start found */
2287 *word_len = i - 1;
2288 break;
2291 /* success */
2292 return 1;
2295 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2297 /* collect the possible completions */
2298 static int
2299 edit_collect_completions (WEdit *edit, long start, int word_len,
2300 char *match_expr, struct selection *compl,
2301 int *num)
2303 int max_len = 0, i, skip;
2304 gsize len = 0;
2305 GString *temp;
2306 mc_search_t *srch;
2308 srch = mc_search_new(match_expr, -1);
2309 if (srch == NULL)
2310 return 0;
2312 srch->search_type = MC_SEARCH_T_REGEX;
2313 srch->is_case_sentitive = TRUE;
2314 srch->search_fn = edit_search_cmd_callback;
2316 /* collect max MAX_WORD_COMPLETIONS completions */
2317 start--;
2318 while (*num < MAX_WORD_COMPLETIONS) {
2319 /* get next match */
2320 if (mc_search_run (srch, (void *) edit, start+1, edit->last_byte, &len) == FALSE)
2321 break;
2322 start = srch->normal_offset;
2324 /* add matched completion if not yet added */
2325 temp = g_string_new("");
2326 for (i = 0; i < len; i++){
2327 skip = edit_get_byte(edit, start+i);
2328 if (isspace(skip))
2329 continue;
2330 g_string_append_c (temp, skip);
2333 skip = 0;
2335 for (i = 0; i < *num; i++) {
2336 if (strncmp
2338 (char *) &compl[i].text[word_len],
2339 (char *) &temp->str[word_len],
2340 max (len, compl[i].len) - word_len
2341 ) == 0) {
2342 skip = 1;
2343 break; /* skip it, already added */
2346 if (skip) {
2347 g_string_free(temp, TRUE);
2348 continue;
2351 compl[*num].text = temp->str;
2352 compl[*num].len = temp->len;
2353 (*num)++;
2354 g_string_free(temp, FALSE);
2356 /* note the maximal length needed for the completion dialog */
2357 if (len > max_len)
2358 max_len = len;
2360 mc_search_free(srch);
2361 return max_len;
2365 * Complete current word using regular expression search
2366 * backwards beginning at the current cursor position.
2368 void
2369 edit_complete_word_cmd (WEdit *edit)
2371 int word_len = 0, i, num_compl = 0, max_len;
2372 long word_start = 0;
2373 unsigned char *bufpos;
2374 char *match_expr;
2375 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2377 /* search start of word to be completed */
2378 if (!edit_find_word_start (edit, &word_start, &word_len))
2379 return;
2381 /* prepare match expression */
2382 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2383 [word_start & M_EDIT_BUF_SIZE];
2385 match_expr = g_strdup_printf ("(^|\\s)%.*s[^\\s\\.=\\+\\{\\}\\[\\]\\(\\)\\\\\\!\\,<>\\?\\/@#\\$%%\\^&\\*\\~\\|\\\"'\\:\\;]+", word_len, bufpos);
2387 /* collect the possible completions */
2388 /* start search from begin to end of file */
2389 max_len =
2390 edit_collect_completions (edit, 0, word_len, match_expr,
2391 (struct selection *) &compl, &num_compl);
2393 if (num_compl > 0) {
2394 /* insert completed word if there is only one match */
2395 if (num_compl == 1) {
2396 for (i = word_len; i < compl[0].len; i++)
2397 edit_insert (edit, *(compl[0].text + i));
2399 /* more than one possible completion => ask the user */
2400 else {
2401 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2402 /* !!! pressed again the selection dialog pops up, but that !!! */
2403 /* !!! seems to require a further internal state !!! */
2404 /*tty_beep (); */
2406 /* let the user select the preferred completion */
2407 editcmd_dialog_completion_show (edit, max_len, word_len,
2408 (struct selection *) &compl,
2409 num_compl);
2413 g_free (match_expr);
2414 /* release memory before return */
2415 for (i = 0; i < num_compl; i++)
2416 g_free (compl[i].text);
2420 void
2421 edit_select_codepage_cmd (WEdit *edit)
2423 #ifdef HAVE_CHARSET
2424 const char *cp_id = NULL;
2425 if (do_select_codepage ()) {
2426 cp_id = get_codepage_id (source_codepage >= 0 ?
2427 source_codepage : display_codepage);
2429 if (cp_id != NULL) {
2430 GIConv conv;
2431 conv = str_crt_conv_from (cp_id);
2432 if (conv != INVALID_CONV) {
2433 if (edit->converter != str_cnv_from_term)
2434 str_close_conv (edit->converter);
2435 edit->converter = conv;
2440 if (cp_id != NULL)
2441 edit->utf8 = str_isutf8 (cp_id);
2444 edit->force = REDRAW_COMPLETELY;
2445 edit_refresh_cmd (edit);
2446 #endif
2449 void
2450 edit_insert_literal_cmd (WEdit *edit)
2452 int char_for_insertion =
2453 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2454 _(" Press any key: "), 0);
2455 edit_execute_key_command (edit, -1,
2456 ascii_alpha_to_cntrl (char_for_insertion));
2459 void
2460 edit_execute_macro_cmd (WEdit *edit)
2462 int command =
2463 CK_Macro (editcmd_dialog_raw_key_query
2464 (_(" Execute Macro "), _(" Press macro hotkey: "),
2465 1));
2466 if (command == CK_Macro (0))
2467 command = CK_Insert_Char;
2469 edit_execute_key_command (edit, command, -1);
2472 void
2473 edit_begin_end_macro_cmd(WEdit *edit)
2475 int command;
2477 /* edit is a pointer to the widget */
2478 if (edit) {
2479 command =
2480 edit->macro_i <
2481 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2482 edit_execute_key_command (edit, command, -1);
2487 edit_load_forward_cmd (WEdit *edit)
2489 if (edit->modified) {
2490 if (edit_query_dialog2
2491 (_("Warning"),
2492 _(" Current text was modified without a file save. \n"
2493 " Continue discards these changes. "), _("C&ontinue"),
2494 _("&Cancel"))) {
2495 edit->force |= REDRAW_COMPLETELY;
2496 return 0;
2499 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2500 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2501 return 1;
2503 edit_stack_iterator++;
2504 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2505 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2506 edit_history_moveto[edit_stack_iterator].line);
2507 return 0;
2508 } else {
2509 return 1;
2511 } else {
2512 return 1;
2517 edit_load_back_cmd (WEdit *edit)
2519 if (edit->modified) {
2520 if (edit_query_dialog2
2521 (_("Warning"),
2522 _(" Current text was modified without a file save. \n"
2523 " Continue discards these changes. "), _("C&ontinue"),
2524 _("&Cancel"))) {
2525 edit->force |= REDRAW_COMPLETELY;
2526 return 0;
2529 if ( edit_stack_iterator > 0 ) {
2530 edit_stack_iterator--;
2531 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2532 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2533 edit_history_moveto[edit_stack_iterator].line);
2534 return 0;
2535 } else {
2536 return 1;
2538 } else {
2539 return 1;
2543 void
2544 edit_get_match_keyword_cmd (WEdit *edit)
2546 int word_len = 0;
2547 int num_def = 0;
2548 int max_len = 0;
2549 int i;
2550 long word_start = 0;
2551 unsigned char *bufpos;
2552 char *match_expr;
2553 char *path = NULL;
2554 char *ptr = NULL;
2555 char *tagfile = NULL;
2557 etags_hash_t def_hash[MAX_DEFINITIONS];
2559 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2560 def_hash[i].filename = NULL;
2563 /* search start of word to be completed */
2564 if (!edit_find_word_start (edit, &word_start, &word_len))
2565 return;
2567 /* prepare match expression */
2568 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2569 [word_start & M_EDIT_BUF_SIZE];
2570 match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
2572 ptr = g_get_current_dir ();
2573 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2574 g_free (ptr);
2576 /* Recursive search file 'TAGS' in parent dirs */
2577 do {
2578 ptr = g_path_get_dirname (path);
2579 g_free(path); path = ptr;
2580 g_free (tagfile);
2581 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2582 if ( exist_file (tagfile) )
2583 break;
2584 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2586 if (tagfile){
2587 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2588 g_free (tagfile);
2590 g_free (path);
2592 max_len = MAX_WIDTH_DEF_DIALOG;
2593 word_len = 0;
2594 if ( num_def > 0 ) {
2595 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2596 (etags_hash_t *) &def_hash,
2597 num_def);
2599 g_free (match_expr);
2602 void
2603 edit_move_block_to_right (WEdit * edit)
2605 long start_mark, end_mark;
2606 long cur_bol, start_bol;
2608 if ( eval_marks (edit, &start_mark, &end_mark) )
2609 return;
2611 start_bol = edit_bol (edit, start_mark);
2612 cur_bol = edit_bol (edit, end_mark - 1);
2613 do {
2614 edit_cursor_move (edit, cur_bol - edit->curs1);
2615 if ( option_fill_tabs_with_spaces ) {
2616 if ( option_fake_half_tabs ) {
2617 insert_spaces_tab (edit, 1);
2618 } else {
2619 insert_spaces_tab (edit, 0);
2621 } else {
2622 edit_insert (edit, '\t');
2624 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2625 if ( cur_bol == 0 ) {
2626 break;
2628 cur_bol = edit_bol (edit, cur_bol - 1);
2629 } while (cur_bol >= start_bol) ;
2630 edit->force |= REDRAW_PAGE;
2633 void
2634 edit_move_block_to_left (WEdit * edit)
2636 long start_mark, end_mark;
2637 long cur_bol, start_bol;
2638 int i, del_tab_width;
2639 int next_char;
2641 if ( eval_marks (edit, &start_mark, &end_mark) )
2642 return;
2644 start_bol = edit_bol (edit, start_mark);
2645 cur_bol = edit_bol (edit, end_mark - 1);
2646 do {
2647 edit_cursor_move (edit, cur_bol - edit->curs1);
2648 if (option_fake_half_tabs) {
2649 del_tab_width = HALF_TAB_SIZE;
2650 } else {
2651 del_tab_width = option_tab_spacing;
2653 next_char = edit_get_byte (edit, edit->curs1);
2654 if ( next_char == '\t' ) {
2655 edit_delete (edit, 1);
2656 } else if ( next_char == ' ' ) {
2657 for (i = 1; i <= del_tab_width; i++) {
2658 if ( next_char == ' ' ) {
2659 edit_delete (edit, 1);
2661 next_char = edit_get_byte (edit, edit->curs1);
2664 if ( cur_bol == 0 ) {
2665 break;
2667 cur_bol = edit_bol (edit, cur_bol - 1);
2668 } while (cur_bol >= start_bol) ;
2669 edit->force |= REDRAW_PAGE;