Ticket #1414: small refactoring before major modifications.
[midnight-commander.git] / edit / editcmd.c
blob7387b933c699b55df970b6f8e4ff2d1702f02309
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" /* COLS */
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 edit_refresh_cmd (WEdit * edit)
128 #ifdef HAVE_SLANG
130 int color;
131 edit_get_syntax_color (edit, -1, &color);
133 tty_touch_screen ();
134 tty_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;
494 save_lock = edit_lock_file (exp);
495 } else {
496 /* filenames equal, check if already locked */
497 if (!edit->locked && !edit->delete_file)
498 save_lock = edit_lock_file (exp);
501 if (different_filename)
504 * Allow user to write into saved (under another name) file
505 * even if original file had r/o user permissions.
507 edit->stat1.st_mode |= S_IWRITE;
510 rv = edit_save_file (edit, exp);
511 switch (rv) {
512 case 1:
513 /* Succesful, so unlock both files */
514 if (different_filename) {
515 if (save_lock)
516 edit_unlock_file (exp);
517 if (edit->locked)
518 edit->locked = edit_unlock_file (edit->filename);
519 } else {
520 if (edit->locked || save_lock)
521 edit->locked = edit_unlock_file (edit->filename);
524 edit_set_filename (edit, exp);
525 g_free (exp);
526 edit->modified = 0;
527 edit->delete_file = 0;
528 if (different_filename)
529 edit_load_syntax (edit, NULL, option_syntax_type);
530 edit->force |= REDRAW_COMPLETELY;
531 return 1;
532 default:
533 edit_error_dialog (_(" Save As "),
534 get_sys_error (_
535 (" Cannot save file. ")));
536 /* fallthrough */
537 case -1:
538 /* Failed, so maintain modify (not save) lock */
539 if (save_lock)
540 edit_unlock_file (exp);
541 g_free (exp);
542 edit->force |= REDRAW_COMPLETELY;
543 return 0;
547 edit->force |= REDRAW_COMPLETELY;
548 return 0;
551 /* {{{ Macro stuff starts here */
553 /* creates a macro file if it doesn't exist */
554 static FILE *edit_open_macro_file (const char *r)
556 gchar *filename;
557 FILE *fd;
558 int file;
559 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
560 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
561 g_free(filename);
562 return 0;
564 close (file);
565 fd = fopen (filename, r);
566 g_free(filename);
567 return fd;
570 #define MAX_MACROS 1024
571 static int saved_macro[MAX_MACROS + 1];
572 static int saved_macros_loaded = 0;
575 This is just to stop the macro file be loaded over and over for keys
576 that aren't defined to anything. On slow systems this could be annoying.
578 static int
579 macro_exists (int k)
581 int i;
582 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
583 if (saved_macro[i] == k)
584 return i;
585 return -1;
588 /* returns 1 on error */
589 static int
590 edit_delete_macro (WEdit * edit, int k)
592 gchar *tmp, *tmp2;
593 struct macro macro[MAX_MACRO_LENGTH];
594 FILE *f, *g;
595 int s, i, n, j = 0;
597 (void) edit;
599 if (saved_macros_loaded)
600 if ((j = macro_exists (k)) < 0)
601 return 0;
602 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
603 g = fopen (tmp , "w");
604 g_free(tmp);
605 if (!g) {
606 edit_error_dialog (_(" Delete macro "),
607 get_sys_error (_(" Cannot open temp file ")));
608 return 1;
610 f = edit_open_macro_file ("r");
611 if (!f) {
612 edit_error_dialog (_(" Delete macro "),
613 get_sys_error (_(" Cannot open macro file ")));
614 fclose (g);
615 return 1;
617 for (;;) {
618 n = fscanf (f, ("key '%d 0': "), &s);
619 if (!n || n == EOF)
620 break;
621 n = 0;
622 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
623 n++;
624 fscanf (f, ";\n");
625 if (s != k) {
626 fprintf (g, ("key '%d 0': "), s);
627 for (i = 0; i < n; i++)
628 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
629 fprintf (g, ";\n");
632 fclose (f);
633 fclose (g);
634 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
635 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
636 if (rename ( tmp, tmp2) == -1) {
637 edit_error_dialog (_(" Delete macro "),
638 get_sys_error (_(" Cannot overwrite macro file ")));
639 g_free(tmp);
640 g_free(tmp2);
641 return 1;
643 g_free(tmp);
644 g_free(tmp2);
646 if (saved_macros_loaded)
647 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
648 return 0;
651 /* returns 0 on error */
652 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
654 FILE *f;
655 int s, i;
657 edit_push_action (edit, KEY_PRESS + edit->start_display);
658 s = editcmd_dialog_raw_key_query (_(" Save macro "),
659 _(" Press the macro's new hotkey: "), 1);
660 edit->force |= REDRAW_COMPLETELY;
661 if (s) {
662 if (edit_delete_macro (edit, s))
663 return 0;
664 f = edit_open_macro_file ("a+");
665 if (f) {
666 fprintf (f, ("key '%d 0': "), s);
667 for (i = 0; i < n; i++)
668 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
669 fprintf (f, ";\n");
670 fclose (f);
671 if (saved_macros_loaded) {
672 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
673 saved_macro[i] = s;
675 return 1;
676 } else
677 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
679 return 0;
682 void edit_delete_macro_cmd (WEdit * edit)
684 int command;
686 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
687 _ (" Press macro hotkey: "), 1);
689 if (!command)
690 return;
692 edit_delete_macro (edit, command);
695 /* return 0 on error */
696 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
698 FILE *f;
699 int s, i = 0, found = 0;
701 (void) edit;
703 if (saved_macros_loaded)
704 if (macro_exists (k) < 0)
705 return 0;
707 if ((f = edit_open_macro_file ("r"))) {
708 struct macro dummy;
709 do {
710 int u;
711 u = fscanf (f, ("key '%d 0': "), &s);
712 if (!u || u == EOF)
713 break;
714 if (!saved_macros_loaded)
715 saved_macro[i++] = s;
716 if (!found) {
717 *n = 0;
718 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
719 (*n)++;
720 } else {
721 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
723 fscanf (f, ";\n");
724 if (s == k)
725 found = 1;
726 } while (!found || !saved_macros_loaded);
727 if (!saved_macros_loaded) {
728 saved_macro[i] = 0;
729 saved_macros_loaded = 1;
731 fclose (f);
732 return found;
733 } else
734 edit_error_dialog (_(" Load macro "),
735 get_sys_error (_(" Cannot open macro file ")));
736 return 0;
739 /* }}} Macro stuff starts here */
741 /* returns 1 on success */
742 int edit_save_confirm_cmd (WEdit * edit)
744 gchar *f = NULL;
746 if (edit_confirm_save) {
747 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
748 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
749 g_free(f);
750 return 0;
752 g_free(f);
754 return edit_save_cmd (edit);
758 /* returns 1 on success */
759 static int
760 edit_save_cmd (WEdit *edit)
762 int res, save_lock = 0;
764 if (!edit->locked && !edit->delete_file)
765 save_lock = edit_lock_file (edit->filename);
766 res = edit_save_file (edit, edit->filename);
768 /* Maintain modify (not save) lock on failure */
769 if ((res > 0 && edit->locked) || save_lock)
770 edit->locked = edit_unlock_file (edit->filename);
772 /* On failure try 'save as', it does locking on its own */
773 if (!res)
774 return edit_save_as_cmd (edit);
775 edit->force |= REDRAW_COMPLETELY;
776 if (res > 0) {
777 edit->delete_file = 0;
778 edit->modified = 0;
781 return 1;
785 /* returns 1 on success */
786 int edit_new_cmd (WEdit * edit)
788 if (edit->modified) {
789 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
790 edit->force |= REDRAW_COMPLETELY;
791 return 0;
794 edit->force |= REDRAW_COMPLETELY;
796 return edit_renew (edit); /* if this gives an error, something has really screwed up */
799 /* returns 1 on error */
800 static int
801 edit_load_file_from_filename (WEdit * edit, char *exp)
803 int prev_locked = edit->locked;
804 char *prev_filename = g_strdup (edit->filename);
806 if (!edit_reload (edit, exp)) {
807 g_free (prev_filename);
808 return 1;
811 if (prev_locked)
812 edit_unlock_file (prev_filename);
813 g_free (prev_filename);
814 return 0;
817 static void
818 edit_load_syntax_file (WEdit * edit)
820 char *extdir;
821 int dir = 0;
823 if (geteuid () == 0) {
824 dir = query_dialog (_("Syntax file edit"),
825 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
826 _("&User"), _("&System Wide"));
829 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
830 if (!exist_file(extdir)) {
831 g_free (extdir);
832 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
835 if (dir == 0) {
836 char *buffer;
838 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
839 check_for_default (extdir, buffer);
840 edit_load_file_from_filename (edit, buffer);
841 g_free (buffer);
842 } else if (dir == 1)
843 edit_load_file_from_filename (edit, extdir);
845 g_free (extdir);
848 static void
849 edit_load_menu_file (WEdit * edit)
851 char *buffer;
852 char *menufile;
853 int dir = 0;
855 dir = query_dialog (
856 _(" Menu edit "),
857 _(" Which menu file do you want to edit? "), D_NORMAL,
858 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
861 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
863 if (!exist_file (menufile)) {
864 g_free (menufile);
865 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
868 switch (dir) {
869 case 0:
870 buffer = g_strdup (EDIT_LOCAL_MENU);
871 check_for_default (menufile, buffer);
872 chmod (buffer, 0600);
873 break;
875 case 1:
876 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
877 check_for_default (menufile, buffer);
878 break;
880 case 2:
881 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
882 if (!exist_file (buffer)) {
883 g_free (buffer);
884 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
886 break;
888 default:
889 g_free (menufile);
890 return;
893 edit_load_file_from_filename (edit, buffer);
895 g_free (buffer);
896 g_free (menufile);
900 edit_load_cmd (WEdit *edit, edit_current_file_t what)
902 char *exp;
904 if (edit->modified
905 && (edit_query_dialog2
906 (_("Warning"),
907 _(" Current text was modified without a file save. \n"
908 " Continue discards these changes. "),
909 _("C&ontinue"), _("&Cancel")) == 1)) {
910 edit->force |= REDRAW_COMPLETELY;
911 return 0;
914 switch (what) {
915 case EDIT_FILE_COMMON:
916 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
917 MC_HISTORY_EDIT_LOAD, edit->filename);
919 if (exp) {
920 if (*exp)
921 edit_load_file_from_filename (edit, exp);
922 g_free (exp);
924 break;
926 case EDIT_FILE_SYNTAX:
927 edit_load_syntax_file (edit);
928 break;
930 case EDIT_FILE_MENU:
931 edit_load_menu_file (edit);
932 break;
934 default:
935 break;
938 edit->force |= REDRAW_COMPLETELY;
939 return 0;
943 if mark2 is -1 then marking is from mark1 to the cursor.
944 Otherwise its between the markers. This handles this.
945 Returns 1 if no text is marked.
947 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
949 if (edit->mark1 != edit->mark2) {
950 if (edit->mark2 >= 0) {
951 *start_mark = min (edit->mark1, edit->mark2);
952 *end_mark = max (edit->mark1, edit->mark2);
953 } else {
954 *start_mark = min (edit->mark1, edit->curs1);
955 *end_mark = max (edit->mark1, edit->curs1);
956 edit->column2 = edit->curs_col;
958 return 0;
959 } else {
960 *start_mark = *end_mark = 0;
961 edit->column2 = edit->column1 = 0;
962 return 1;
966 #define space_width 1
968 void
969 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
971 long cursor;
972 int i, col;
973 cursor = edit->curs1;
974 col = edit_get_col (edit);
975 for (i = 0; i < size; i++) {
976 if (data[i] == '\n') { /* fill in and move to next line */
977 int l;
978 long p;
979 if (edit_get_byte (edit, edit->curs1) != '\n') {
980 l = width - (edit_get_col (edit) - col);
981 while (l > 0) {
982 edit_insert (edit, ' ');
983 l -= space_width;
986 for (p = edit->curs1;; p++) {
987 if (p == edit->last_byte) {
988 edit_cursor_move (edit, edit->last_byte - edit->curs1);
989 edit_insert_ahead (edit, '\n');
990 p++;
991 break;
993 if (edit_get_byte (edit, p) == '\n') {
994 p++;
995 break;
998 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
999 l = col - edit_get_col (edit);
1000 while (l >= space_width) {
1001 edit_insert (edit, ' ');
1002 l -= space_width;
1004 continue;
1006 edit_insert (edit, data[i]);
1008 edit_cursor_move (edit, cursor - edit->curs1);
1011 #define TEMP_BUF_LEN 1024
1014 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1016 long cursor;
1017 int i, col;
1018 int blocklen = -1, width;
1019 unsigned char *data;
1020 cursor = edit->curs1;
1021 col = edit_get_col (edit);
1022 data = g_malloc (TEMP_BUF_LEN);
1023 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1024 for (width = 0; width < blocklen; width++) {
1025 if (data[width] == '\n')
1026 break;
1028 for (i = 0; i < blocklen; i++) {
1029 if (data[i] == '\n') { /* fill in and move to next line */
1030 int l;
1031 long p;
1032 if (edit_get_byte (edit, edit->curs1) != '\n') {
1033 l = width - (edit_get_col (edit) - col);
1034 while (l > 0) {
1035 edit_insert (edit, ' ');
1036 l -= space_width;
1039 for (p = edit->curs1;; p++) {
1040 if (p == edit->last_byte) {
1041 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1042 edit_insert_ahead (edit, '\n');
1043 p++;
1044 break;
1046 if (edit_get_byte (edit, p) == '\n') {
1047 p++;
1048 break;
1051 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1052 l = col - edit_get_col (edit);
1053 while (l >= space_width) {
1054 edit_insert (edit, ' ');
1055 l -= space_width;
1057 continue;
1059 edit_insert (edit, data[i]);
1062 edit_cursor_move (edit, cursor - edit->curs1);
1063 g_free(data);
1064 edit->force |= REDRAW_PAGE;
1065 return blocklen;
1068 void
1069 edit_block_copy_cmd (WEdit *edit)
1071 long start_mark, end_mark, current = edit->curs1;
1072 int size;
1073 unsigned char *copy_buf;
1075 edit_update_curs_col (edit);
1076 if (eval_marks (edit, &start_mark, &end_mark))
1077 return;
1079 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1081 /* all that gets pushed are deletes hence little space is used on the stack */
1083 edit_push_markers (edit);
1085 if (column_highlighting) {
1086 edit_insert_column_of_text (edit, copy_buf, size,
1087 abs (edit->column2 - edit->column1));
1088 } else {
1089 while (size--)
1090 edit_insert_ahead (edit, copy_buf[size]);
1093 g_free (copy_buf);
1094 edit_scroll_screen_over_cursor (edit);
1096 if (column_highlighting) {
1097 edit_set_markers (edit, 0, 0, 0, 0);
1098 edit_push_action (edit, COLUMN_ON);
1099 column_highlighting = 0;
1100 } else if (start_mark < current && end_mark > current)
1101 edit_set_markers (edit, start_mark,
1102 end_mark + end_mark - start_mark, 0, 0);
1104 edit->force |= REDRAW_PAGE;
1108 void
1109 edit_block_move_cmd (WEdit *edit)
1111 long count;
1112 long current;
1113 unsigned char *copy_buf;
1114 long start_mark, end_mark;
1115 int deleted = 0;
1116 int x = 0;
1118 if (eval_marks (edit, &start_mark, &end_mark))
1119 return;
1120 if (column_highlighting) {
1121 edit_update_curs_col (edit);
1122 x = edit->curs_col;
1123 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1124 if ((x > edit->column1 && x < edit->column2)
1125 || (x > edit->column2 && x < edit->column1))
1126 return;
1127 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1128 return;
1130 if ((end_mark - start_mark) > option_max_undo / 2)
1131 if (edit_query_dialog2
1132 (_("Warning"),
1134 (" Block is large, you may not be able to undo this action. "),
1135 _("C&ontinue"), _("&Cancel")))
1136 return;
1138 edit_push_markers (edit);
1139 current = edit->curs1;
1140 if (column_highlighting) {
1141 int size, c1, c2, line;
1142 line = edit->curs_line;
1143 if (edit->mark2 < 0)
1144 edit_mark_cmd (edit, 0);
1145 c1 = min (edit->column1, edit->column2);
1146 c2 = max (edit->column1, edit->column2);
1147 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1148 if (x < c2) {
1149 edit_block_delete_cmd (edit);
1150 deleted = 1;
1152 edit_move_to_line (edit, line);
1153 edit_cursor_move (edit,
1154 edit_move_forward3 (edit,
1155 edit_bol (edit, edit->curs1),
1156 x, 0) - edit->curs1);
1157 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1158 if (!deleted) {
1159 line = edit->curs_line;
1160 edit_update_curs_col (edit);
1161 x = edit->curs_col;
1162 edit_block_delete_cmd (edit);
1163 edit_move_to_line (edit, line);
1164 edit_cursor_move (edit,
1165 edit_move_forward3 (edit,
1166 edit_bol (edit,
1167 edit->curs1),
1168 x, 0) - edit->curs1);
1170 edit_set_markers (edit, 0, 0, 0, 0);
1171 edit_push_action (edit, COLUMN_ON);
1172 column_highlighting = 0;
1173 } else {
1174 copy_buf = g_malloc (end_mark - start_mark);
1175 edit_cursor_move (edit, start_mark - edit->curs1);
1176 edit_scroll_screen_over_cursor (edit);
1177 count = start_mark;
1178 while (count < end_mark) {
1179 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1180 count++;
1182 edit_scroll_screen_over_cursor (edit);
1183 edit_cursor_move (edit,
1184 current - edit->curs1 -
1185 (((current - edit->curs1) >
1186 0) ? end_mark - start_mark : 0));
1187 edit_scroll_screen_over_cursor (edit);
1188 while (count-- > start_mark)
1189 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1190 edit_set_markers (edit, edit->curs1,
1191 edit->curs1 + end_mark - start_mark, 0, 0);
1193 edit_scroll_screen_over_cursor (edit);
1194 g_free (copy_buf);
1195 edit->force |= REDRAW_PAGE;
1198 static void
1199 edit_delete_column_of_text (WEdit * edit)
1201 long p, q, r, m1, m2;
1202 int b, c, d;
1203 int n;
1205 eval_marks (edit, &m1, &m2);
1206 n = edit_move_forward (edit, m1, 0, m2) + 1;
1207 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1208 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1210 b = min (c, d);
1211 c = max (c, d);
1213 while (n--) {
1214 r = edit_bol (edit, edit->curs1);
1215 p = edit_move_forward3 (edit, r, b, 0);
1216 q = edit_move_forward3 (edit, r, c, 0);
1217 if (p < m1)
1218 p = m1;
1219 if (q > m2)
1220 q = m2;
1221 edit_cursor_move (edit, p - edit->curs1);
1222 while (q > p) { /* delete line between margins */
1223 if (edit_get_byte (edit, edit->curs1) != '\n')
1224 edit_delete (edit, 1);
1225 q--;
1227 if (n) /* move to next line except on the last delete */
1228 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1232 /* if success return 0 */
1233 static int
1234 edit_block_delete (WEdit *edit)
1236 long count;
1237 long start_mark, end_mark;
1238 if (eval_marks (edit, &start_mark, &end_mark))
1239 return 0;
1240 if (column_highlighting && edit->mark2 < 0)
1241 edit_mark_cmd (edit, 0);
1242 if ((end_mark - start_mark) > option_max_undo / 2) {
1243 /* Warning message with a query to continue or cancel the operation */
1244 if (edit_query_dialog2
1245 (_("Warning"),
1247 (" Block is large, you may not be able to undo this action. "),
1248 _("C&ontinue"), _("&Cancel"))) {
1249 return 1;
1252 edit_push_markers (edit);
1253 edit_cursor_move (edit, start_mark - edit->curs1);
1254 edit_scroll_screen_over_cursor (edit);
1255 count = start_mark;
1256 if (start_mark < end_mark) {
1257 if (column_highlighting) {
1258 if (edit->mark2 < 0)
1259 edit_mark_cmd (edit, 0);
1260 edit_delete_column_of_text (edit);
1261 } else {
1262 while (count < end_mark) {
1263 edit_delete (edit, 1);
1264 count++;
1268 edit_set_markers (edit, 0, 0, 0, 0);
1269 edit->force |= REDRAW_PAGE;
1270 return 0;
1273 /* returns 1 if canceelled by user */
1274 int edit_block_delete_cmd (WEdit * edit)
1276 long start_mark, end_mark;
1277 if (eval_marks (edit, &start_mark, &end_mark)) {
1278 edit_delete_line (edit);
1279 return 0;
1281 return edit_block_delete (edit);
1284 #define INPUT_INDEX 9
1286 static gboolean
1287 editcmd_find (WEdit *edit, gsize *len)
1289 gsize search_start = edit->search_start;
1290 gsize search_end;
1292 if (edit->replace_backwards) {
1293 search_end = edit->last_byte;
1294 while ((int) search_start >= 0) {
1295 if (search_end > search_start + edit->search->original_len && mc_search_is_fixed_search_str(edit->search))
1296 search_end = search_start + edit->search->original_len;
1297 if ( mc_search_run(edit->search, (void *) edit, search_start, search_end, len)
1298 && edit->search->normal_offset == search_start )
1300 return TRUE;
1302 search_start--;
1304 edit->search->error_str = g_strdup(_(" Search string not found "));
1305 } else {
1306 return mc_search_run(edit->search, (void *) edit, edit->search_start, edit->last_byte, len);
1308 return FALSE;
1312 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1313 (and the above) routines to work properly - paul */
1315 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1317 static char *
1318 edit_replace_cmd__conv_to_display(char *str)
1320 #ifdef HAVE_CHARSET
1321 GString *tmp;
1322 tmp = str_convert_to_display (str);
1324 if (tmp && tmp->len){
1325 g_free(str);
1326 str = tmp->str;
1328 g_string_free (tmp, FALSE);
1329 return str;
1330 #else
1331 return g_strdup(str);
1332 #endif
1335 static char *
1336 edit_replace_cmd__conv_to_input(char *str)
1338 #ifdef HAVE_CHARSET
1339 GString *tmp;
1340 tmp = str_convert_to_input (str);
1342 if (tmp && tmp->len){
1343 g_free(str);
1344 str = tmp->str;
1346 g_string_free (tmp, FALSE);
1347 return str;
1348 #else
1349 return g_strdup(str);
1350 #endif
1352 /* call with edit = 0 before shutdown to close memory leaks */
1353 void
1354 edit_replace_cmd (WEdit *edit, int again)
1356 /* 1 = search string, 2 = replace with */
1357 static char *saved1 = NULL; /* saved default[123] */
1358 static char *saved2 = NULL;
1359 char *input1 = NULL; /* user input from the dialog */
1360 char *input2 = NULL;
1361 int replace_yes;
1362 long times_replaced = 0, last_search;
1363 gboolean once_found = FALSE;
1365 if (!edit) {
1366 g_free (saved1), saved1 = NULL;
1367 g_free (saved2), saved2 = NULL;
1368 return;
1371 last_search = edit->last_byte;
1373 edit->force |= REDRAW_COMPLETELY;
1375 if (again && !saved1 && !saved2)
1376 again = 0;
1378 if (again) {
1379 input1 = g_strdup (saved1 ? saved1 : "");
1380 input2 = g_strdup (saved2 ? saved2 : "");
1381 } else {
1382 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1383 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1385 edit_push_action (edit, KEY_PRESS + edit->start_display);
1387 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1389 g_free (disp1);
1390 g_free (disp2);
1392 if (input1 == NULL || *input1 == '\0') {
1393 edit->force = REDRAW_COMPLETELY;
1394 goto cleanup;
1397 input1 = edit_replace_cmd__conv_to_input(input1);
1398 input2 = edit_replace_cmd__conv_to_input(input2);
1400 g_free (saved1), saved1 = g_strdup (input1);
1401 g_free (saved2), saved2 = g_strdup (input2);
1403 if (edit->search) {
1404 mc_search_free(edit->search);
1405 edit->search = NULL;
1409 if (!edit->search) {
1410 edit->search = mc_search_new(input1, -1);
1411 if (edit->search == NULL) {
1412 edit->search_start = edit->curs1;
1413 return;
1415 edit->search->search_type = edit->search_type;
1416 edit->search->is_all_charsets = edit->all_codepages;
1417 edit->search->is_case_sentitive = edit->replace_case;
1418 edit->search->search_fn = edit_search_cmd_callback;
1421 if (edit->found_len && edit->search_start == edit->found_start + 1
1422 && edit->replace_backwards)
1423 edit->search_start--;
1425 if (edit->found_len && edit->search_start == edit->found_start - 1
1426 && !edit->replace_backwards)
1427 edit->search_start++;
1429 do {
1430 gsize len = 0;
1431 long new_start;
1433 if (! editcmd_find(edit, &len)) {
1434 if (!(edit->search->error == MC_SEARCH_E_OK ||
1435 (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND))) {
1436 edit_error_dialog (_ ("Search"), edit->search->error_str);
1438 break;
1440 once_found = TRUE;
1441 new_start = edit->search->normal_offset;
1443 edit->search_start = new_start = edit->search->normal_offset;
1444 /*returns negative on not found or error in pattern */
1446 if (edit->search_start >= 0) {
1447 guint i;
1449 edit->found_start = edit->search_start;
1450 i = edit->found_len = len;
1452 edit_cursor_move (edit, edit->search_start - edit->curs1);
1453 edit_scroll_screen_over_cursor (edit);
1455 replace_yes = 1;
1457 if (edit->replace_mode == 0) {
1458 int l;
1459 l = edit->curs_row - edit->num_widget_lines / 3;
1460 if (l > 0)
1461 edit_scroll_downward (edit, l);
1462 if (l < 0)
1463 edit_scroll_upward (edit, -l);
1465 edit_scroll_screen_over_cursor (edit);
1466 edit->force |= REDRAW_PAGE;
1467 edit_render_keypress (edit);
1469 /*so that undo stops at each query */
1470 edit_push_key_press (edit);
1471 /* and prompt 2/3 down */
1472 switch (editcmd_dialog_replace_prompt_show (edit, input1, input2, -1, -1)) {
1473 case B_ENTER:
1474 replace_yes = 1;
1475 break;
1476 case B_SKIP_REPLACE:
1477 replace_yes = 0;
1478 break;
1479 case B_REPLACE_ALL:
1480 edit->replace_mode=1;
1481 break;
1482 case B_CANCEL:
1483 replace_yes = 0;
1484 edit->replace_mode = -1;
1485 break;
1488 if (replace_yes) { /* delete then insert new */
1489 GString *repl_str, *tmp_str;
1490 tmp_str = g_string_new(input2);
1492 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1493 g_string_free(tmp_str, TRUE);
1494 if (edit->search->error != MC_SEARCH_E_OK)
1496 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1497 break;
1500 while (i--)
1501 edit_delete (edit, 1);
1503 while (++i < repl_str->len)
1504 edit_insert (edit, repl_str->str[i]);
1506 g_string_free(repl_str, TRUE);
1507 edit->found_len = i;
1509 /* so that we don't find the same string again */
1510 if (edit->replace_backwards) {
1511 last_search = edit->search_start;
1512 edit->search_start--;
1513 } else {
1514 edit->search_start += i;
1515 last_search = edit->last_byte;
1517 edit_scroll_screen_over_cursor (edit);
1518 } else {
1519 const char *msg = _(" Replace ");
1520 /* try and find from right here for next search */
1521 edit->search_start = edit->curs1;
1522 edit_update_curs_col (edit);
1524 edit->force |= REDRAW_PAGE;
1525 edit_render_keypress (edit);
1526 if (times_replaced) {
1527 message (D_NORMAL, msg, _(" %ld replacements made. "),
1528 times_replaced);
1529 } else
1530 query_dialog (msg, _(" Search string not found "),
1531 D_NORMAL, 1, _("&OK"));
1532 edit->replace_mode = -1;
1534 } while (edit->replace_mode >= 0);
1536 edit->force = REDRAW_COMPLETELY;
1537 edit_scroll_screen_over_cursor (edit);
1538 cleanup:
1539 g_free (input1);
1540 g_free (input2);
1544 void edit_search_cmd (WEdit * edit, int again)
1546 char *search_string = NULL, *search_string_dup = NULL;
1548 gsize len = 0;
1550 if (!edit)
1551 return;
1553 if (edit->search != NULL) {
1554 search_string = g_strndup(edit->search->original, edit->search->original_len);
1555 search_string_dup = search_string;
1556 } else {
1557 GList *history;
1558 history = history_get (MC_HISTORY_SHARED_SEARCH);
1559 if (history != NULL && history->data != NULL) {
1560 search_string_dup = search_string = (char *) g_strdup(history->data);
1561 history = g_list_first (history);
1562 g_list_foreach (history, (GFunc) g_free, NULL);
1563 g_list_free (history);
1565 edit->search_start = edit->curs1;
1568 if (!again) {
1569 #ifdef HAVE_CHARSET
1570 GString *tmp;
1571 if (search_string && *search_string) {
1572 tmp = str_convert_to_display (search_string);
1574 g_free(search_string_dup);
1575 search_string_dup = NULL;
1577 if (tmp && tmp->len)
1578 search_string = search_string_dup = tmp->str;
1579 g_string_free (tmp, FALSE);
1581 #endif /* HAVE_CHARSET */
1582 editcmd_dialog_search_show (edit, &search_string);
1583 #ifdef HAVE_CHARSET
1584 if (search_string && *search_string) {
1585 tmp = str_convert_to_input (search_string);
1586 if (tmp && tmp->len)
1587 search_string = tmp->str;
1589 g_string_free (tmp, FALSE);
1591 if (search_string_dup)
1592 g_free(search_string_dup);
1594 #endif /* HAVE_CHARSET */
1596 edit_push_action (edit, KEY_PRESS + edit->start_display);
1598 if (!search_string) {
1599 edit->force |= REDRAW_COMPLETELY;
1600 edit_scroll_screen_over_cursor (edit);
1601 return;
1604 if (edit->search) {
1605 mc_search_free(edit->search);
1606 edit->search = NULL;
1610 if (!edit->search) {
1611 edit->search = mc_search_new(search_string, -1);
1612 if (edit->search == NULL) {
1613 edit->search_start = edit->curs1;
1614 return;
1616 edit->search->search_type = edit->search_type;
1617 edit->search->is_all_charsets = edit->all_codepages;
1618 edit->search->is_case_sentitive = edit->replace_case;
1619 edit->search->search_fn = edit_search_cmd_callback;
1622 if (search_create_bookmark) {
1623 edit_search_cmd_search_create_bookmark(edit);
1624 } else {
1625 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1626 edit->search_start--;
1628 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1629 edit->search_start++;
1632 if (editcmd_find(edit, &len)) {
1633 edit->found_start = edit->search_start = edit->search->normal_offset;
1634 edit->found_len = len;
1636 edit_cursor_move (edit, edit->search_start - edit->curs1);
1637 edit_scroll_screen_over_cursor (edit);
1638 if (edit->replace_backwards)
1639 edit->search_start--;
1640 else
1641 edit->search_start++;
1642 } else {
1643 edit->search_start = edit->curs1;
1644 if (edit->search->error_str)
1645 edit_error_dialog (_ ("Search"), edit->search->error_str);
1649 edit->force |= REDRAW_COMPLETELY;
1650 edit_scroll_screen_over_cursor (edit);
1655 * Check if it's OK to close the editor. If there are unsaved changes,
1656 * ask user. Return 1 if it's OK to exit, 0 to continue editing.
1659 edit_ok_to_exit (WEdit *edit)
1661 if (!edit->modified)
1662 return 1;
1664 switch (edit_query_dialog3
1665 (_("Quit"), _(" File was modified, Save with exit? "),
1666 _("&Cancel quit"), _("&Yes"), _("&No"))) {
1667 case 1:
1668 edit_push_markers (edit);
1669 edit_set_markers (edit, 0, 0, 0, 0);
1670 if (!edit_save_cmd (edit))
1671 return 0;
1672 break;
1673 case 2:
1674 break;
1675 case 0:
1676 case -1:
1677 return 0;
1680 return 1;
1683 /* Return a null terminated length of text. Result must be g_free'd */
1684 static unsigned char *
1685 edit_get_block (WEdit *edit, long start, long finish, int *l)
1687 unsigned char *s, *r;
1688 r = s = g_malloc (finish - start + 1);
1689 if (column_highlighting) {
1690 *l = 0;
1691 /* copy from buffer, excluding chars that are out of the column 'margins' */
1692 while (start < finish) {
1693 int c, x;
1694 x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
1695 start);
1696 c = edit_get_byte (edit, start);
1697 if ((x >= edit->column1 && x < edit->column2)
1698 || (x >= edit->column2 && x < edit->column1) || c == '\n') {
1699 *s++ = c;
1700 (*l)++;
1702 start++;
1704 } else {
1705 *l = finish - start;
1706 while (start < finish)
1707 *s++ = edit_get_byte (edit, start++);
1709 *s = 0;
1710 return r;
1713 /* save block, returns 1 on success */
1715 edit_save_block (WEdit * edit, const char *filename, long start,
1716 long finish)
1718 int len, file;
1720 if ((file =
1721 mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
1722 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
1723 return 0;
1725 if (column_highlighting) {
1726 int r;
1727 r = mc_write (file, VERTICAL_MAGIC, sizeof(VERTICAL_MAGIC));
1728 if (r > 0) {
1729 unsigned char *block, *p;
1730 p = block = edit_get_block (edit, start, finish, &len);
1731 while (len) {
1732 r = mc_write (file, p, len);
1733 if (r < 0)
1734 break;
1735 p += r;
1736 len -= r;
1738 g_free (block);
1740 } else {
1741 unsigned char *buf;
1742 int i = start, end;
1743 len = finish - start;
1744 buf = g_malloc (TEMP_BUF_LEN);
1745 while (start != finish) {
1746 end = min (finish, start + TEMP_BUF_LEN);
1747 for (; i < end; i++)
1748 buf[i - start] = edit_get_byte (edit, i);
1749 len -= mc_write (file, (char *) buf, end - start);
1750 start = end;
1752 g_free (buf);
1754 mc_close (file);
1755 if (len)
1756 return 0;
1757 return 1;
1760 /* copies a block to clipboard file */
1761 static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
1763 int ret;
1764 gchar *tmp;
1765 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1766 ret = edit_save_block (edit, tmp, start, finish);
1767 g_free(tmp);
1768 return ret;
1772 void edit_paste_from_history (WEdit *edit)
1774 (void) edit;
1775 edit_error_dialog (_(" Error "), _(" This function is not implemented. "));
1778 int edit_copy_to_X_buf_cmd (WEdit * edit)
1780 long start_mark, end_mark;
1781 if (eval_marks (edit, &start_mark, &end_mark))
1782 return 0;
1783 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1784 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
1785 return 1;
1787 edit_mark_cmd (edit, 1);
1788 return 0;
1791 int edit_cut_to_X_buf_cmd (WEdit * edit)
1793 long start_mark, end_mark;
1794 if (eval_marks (edit, &start_mark, &end_mark))
1795 return 0;
1796 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
1797 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
1798 return 1;
1800 edit_block_delete_cmd (edit);
1801 edit_mark_cmd (edit, 1);
1802 return 0;
1805 void edit_paste_from_X_buf_cmd (WEdit * edit)
1807 gchar *tmp;
1808 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1809 edit_insert_file (edit, tmp);
1810 g_free(tmp);
1815 * Ask user for the line and go to that line.
1816 * Negative numbers mean line from the end (i.e. -1 is the last line).
1818 void
1819 edit_goto_cmd (WEdit *edit)
1821 char *f;
1822 static long line = 0; /* line as typed, saved as default */
1823 long l;
1824 char *error;
1825 char s[32];
1827 g_snprintf (s, sizeof (s), "%ld", line);
1828 f = input_dialog (_(" Goto line "), _(" Enter line: "), MC_HISTORY_EDIT_GOTO_LINE,
1829 line ? s : "");
1830 if (!f)
1831 return;
1833 if (!*f) {
1834 g_free (f);
1835 return;
1838 l = strtol (f, &error, 0);
1839 if (*error) {
1840 g_free (f);
1841 return;
1844 line = l;
1845 if (l < 0)
1846 l = edit->total_lines + l + 2;
1847 edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
1848 edit_move_to_line (edit, l - 1);
1849 edit->force |= REDRAW_COMPLETELY;
1850 g_free (f);
1854 /* Return 1 on success */
1856 edit_save_block_cmd (WEdit *edit)
1858 long start_mark, end_mark;
1859 char *exp, *tmp;
1861 if (eval_marks (edit, &start_mark, &end_mark))
1862 return 1;
1864 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1865 exp =
1866 input_expand_dialog (_(" Save Block "), _(" Enter file name: "),
1867 MC_HISTORY_EDIT_SAVE_BLOCK,
1868 tmp);
1869 g_free(tmp);
1870 edit_push_action (edit, KEY_PRESS + edit->start_display);
1871 if (exp) {
1872 if (!*exp) {
1873 g_free (exp);
1874 return 0;
1875 } else {
1876 if (edit_save_block (edit, exp, start_mark, end_mark)) {
1877 g_free (exp);
1878 edit->force |= REDRAW_COMPLETELY;
1879 return 1;
1880 } else {
1881 g_free (exp);
1882 edit_error_dialog (_(" Save Block "),
1883 get_sys_error (_
1884 (" Cannot save file. ")));
1888 edit->force |= REDRAW_COMPLETELY;
1889 return 0;
1893 /* returns 1 on success */
1895 edit_insert_file_cmd (WEdit *edit)
1897 gchar *tmp;
1898 char *exp;
1900 tmp = concat_dir_and_file (home_dir, EDIT_CLIP_FILE);
1901 exp = input_expand_dialog (_(" Insert File "), _(" Enter file name: "),
1902 MC_HISTORY_EDIT_INSERT_FILE,
1903 tmp);
1904 g_free(tmp);
1905 edit_push_action (edit, KEY_PRESS + edit->start_display);
1906 if (exp) {
1907 if (!*exp) {
1908 g_free (exp);
1909 return 0;
1910 } else {
1911 if (edit_insert_file (edit, exp)) {
1912 g_free (exp);
1913 edit->force |= REDRAW_COMPLETELY;
1914 return 1;
1915 } else {
1916 g_free (exp);
1917 edit_error_dialog (_(" Insert File "),
1918 get_sys_error (_
1919 (" Cannot insert file. ")));
1923 edit->force |= REDRAW_COMPLETELY;
1924 return 0;
1927 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
1928 int edit_sort_cmd (WEdit * edit)
1930 static char *old = 0;
1931 char *exp, *tmp;
1932 long start_mark, end_mark;
1933 int e;
1935 if (eval_marks (edit, &start_mark, &end_mark)) {
1936 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
1937 return 0;
1940 tmp = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
1941 edit_save_block (edit, tmp, start_mark, end_mark);
1942 g_free(tmp);
1944 exp = input_dialog (_(" Run Sort "),
1945 _(" Enter sort options (see manpage) separated by whitespace: "),
1946 MC_HISTORY_EDIT_SORT, (old != NULL) ? old : "");
1948 if (!exp)
1949 return 1;
1950 g_free (old);
1951 old = exp;
1952 tmp = g_strconcat (" sort ", exp, " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE, " > ",
1953 home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
1954 e = system (tmp);
1955 g_free(tmp);
1956 if (e) {
1957 if (e == -1 || e == 127) {
1958 edit_error_dialog (_(" Sort "),
1959 get_sys_error (_(" Cannot execute sort command ")));
1960 } else {
1961 char q[8];
1962 sprintf (q, "%d ", e);
1963 tmp = g_strconcat (_(" Sort returned non-zero: "), q, (char *) NULL);
1964 edit_error_dialog (_(" Sort "), tmp);
1965 g_free(tmp);
1967 return -1;
1970 edit->force |= REDRAW_COMPLETELY;
1972 if (edit_block_delete_cmd (edit))
1973 return 1;
1974 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
1975 edit_insert_file (edit, tmp);
1976 g_free(tmp);
1977 return 0;
1981 * Ask user for a command, execute it and paste its output back to the
1982 * editor.
1985 edit_ext_cmd (WEdit *edit)
1987 char *exp, *tmp;
1988 int e;
1990 exp =
1991 input_dialog (_("Paste output of external command"),
1992 _("Enter shell command(s):"),
1993 MC_HISTORY_EDIT_PASTE_EXTCMD, NULL);
1995 if (!exp)
1996 return 1;
1998 tmp = g_strconcat (exp, " > ", home_dir, PATH_SEP_STR EDIT_TEMP_FILE, (char *) NULL);
1999 e = system (tmp);
2000 g_free(tmp);
2001 g_free (exp);
2003 if (e) {
2004 edit_error_dialog (_("External command"),
2005 get_sys_error (_("Cannot execute command")));
2006 return -1;
2009 edit->force |= REDRAW_COMPLETELY;
2010 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
2011 edit_insert_file (edit, tmp);
2012 g_free(tmp);
2013 return 0;
2016 /* if block is 1, a block must be highlighted and the shell command
2017 processes it. If block is 0 the shell command is a straight system
2018 command, that just produces some output which is to be inserted */
2019 void
2020 edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
2022 long start_mark, end_mark;
2023 char buf[BUFSIZ];
2024 FILE *script_home = NULL;
2025 FILE *script_src = NULL;
2026 FILE *block_file = NULL;
2027 gchar *o, *h, *b, *tmp;
2028 char *quoted_name = NULL;
2030 o = g_strconcat (mc_home, shell_cmd, (char *) NULL); /* original source script */
2031 h = g_strconcat (home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL); /* home script */
2032 b = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE); /* block file */
2034 if (!(script_home = fopen (h, "r"))) {
2035 if (!(script_home = fopen (h, "w"))) {
2036 tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
2037 edit_error_dialog ("", get_sys_error (tmp));
2038 g_free(tmp);
2039 goto edit_block_process_cmd__EXIT;
2041 if (!(script_src = fopen (o, "r"))) {
2042 o = g_strconcat (mc_home_alt, shell_cmd, (char *) NULL);
2043 if (!(script_src = fopen (o, "r"))) {
2044 fclose (script_home);
2045 unlink (h);
2046 tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
2047 edit_error_dialog ("", get_sys_error (tmp));
2048 g_free(tmp);
2049 goto edit_block_process_cmd__EXIT;
2052 while (fgets (buf, sizeof (buf), script_src))
2053 fputs (buf, script_home);
2054 if (fclose (script_home)) {
2055 tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
2056 edit_error_dialog ("", get_sys_error (tmp));
2057 g_free(tmp);
2058 goto edit_block_process_cmd__EXIT;
2060 chmod (h, 0700);
2061 tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
2062 edit_error_dialog ("", get_sys_error (tmp));
2063 g_free(tmp);
2066 open_error_pipe ();
2068 if (block) { /* for marked block run indent formatter */
2069 if (eval_marks (edit, &start_mark, &end_mark)) {
2070 edit_error_dialog (_("Process block"),
2072 (" You must first highlight a block of text. "));
2073 goto edit_block_process_cmd__EXIT;
2075 edit_save_block (edit, b, start_mark, end_mark);
2076 quoted_name = name_quote (edit->filename, 0);
2078 * Run script.
2079 * Initial space is to avoid polluting bash history.
2080 * Arguments:
2081 * $1 - name of the edited file (to check its extension etc).
2082 * $2 - file containing the current block.
2083 * $3 - file where error messages should be put
2084 * (for compatibility with old scripts).
2086 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ", quoted_name,
2087 " ", home_dir, PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
2088 system (tmp);
2089 g_free(tmp);
2090 } else {
2092 * No block selected, just execute the command for the file.
2093 * Arguments:
2094 * $1 - name of the edited file.
2096 tmp = g_strconcat (" ", home_dir, PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
2097 quoted_name, (char *) NULL);
2098 system (tmp);
2099 g_free(tmp);
2101 g_free (quoted_name);
2102 close_error_pipe (D_NORMAL, NULL);
2104 edit_refresh_cmd (edit);
2105 edit->force |= REDRAW_COMPLETELY;
2107 /* insert result block */
2108 if (block) {
2109 if (edit_block_delete_cmd (edit))
2110 goto edit_block_process_cmd__EXIT;
2111 edit_insert_file (edit, b);
2112 if ((block_file = fopen (b, "w")))
2113 fclose (block_file);
2114 goto edit_block_process_cmd__EXIT;
2116 edit_block_process_cmd__EXIT:
2117 g_free(b);
2118 g_free(h);
2119 g_free(o);
2120 return;
2123 /* prints at the cursor */
2124 /* returns the number of chars printed */
2125 int edit_print_string (WEdit * e, const char *s)
2127 int i = 0;
2128 while (s[i])
2129 edit_execute_cmd (e, -1, (unsigned char) s[i++]);
2130 e->force |= REDRAW_COMPLETELY;
2131 edit_update_screen (e);
2132 return i;
2136 static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
2138 FILE *p = 0;
2139 char *s;
2141 to = name_quote (to, 0);
2142 subject = name_quote (subject, 0);
2143 cc = name_quote (cc, 0);
2144 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "" , cc, " ", to, (char *) NULL);
2145 g_free (to);
2146 g_free (subject);
2147 g_free (cc);
2149 if (s) {
2150 p = popen (s, "w");
2151 g_free (s);
2154 if (p) {
2155 long i;
2156 for (i = 0; i < edit->last_byte; i++)
2157 fputc (edit_get_byte (edit, i), p);
2158 pclose (p);
2162 #define MAIL_DLG_HEIGHT 12
2164 void edit_mail_dialog (WEdit * edit)
2166 char *tmail_to;
2167 char *tmail_subject;
2168 char *tmail_cc;
2170 static char *mail_cc_last = 0;
2171 static char *mail_subject_last = 0;
2172 static char *mail_to_last = 0;
2174 QuickDialog Quick_input =
2175 {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
2176 "[Input Line Keys]", 0, 0};
2178 QuickWidget quick_widgets[] =
2180 {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
2181 0, NULL, NULL, NULL},
2182 {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
2183 0, NULL, NULL, NULL},
2184 {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2185 0, "mail-dlg-input", NULL, NULL},
2186 {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
2187 0, 0, NULL, NULL},
2188 {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2189 0, "mail-dlg-input-2", NULL, NULL},
2190 {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
2191 0, 0, NULL, NULL},
2192 {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
2193 0, "mail-dlg-input-3", NULL, NULL},
2194 {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
2195 0, 0, NULL, NULL},
2196 {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2197 0, 0, NULL, NULL},
2198 NULL_QuickWidget};
2200 quick_widgets[2].str_result = &tmail_cc;
2201 quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
2202 quick_widgets[4].str_result = &tmail_subject;
2203 quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
2204 quick_widgets[6].str_result = &tmail_to;
2205 quick_widgets[6].text = mail_to_last ? mail_to_last : "";
2207 Quick_input.widgets = quick_widgets;
2209 if (quick_dialog (&Quick_input) != B_CANCEL) {
2210 g_free (mail_cc_last);
2211 g_free (mail_subject_last);
2212 g_free (mail_to_last);
2213 mail_cc_last = tmail_cc;
2214 mail_subject_last = tmail_subject;
2215 mail_to_last = tmail_to;
2216 pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
2221 /*******************/
2222 /* Word Completion */
2223 /*******************/
2225 static gboolean is_break_char(char c)
2227 return (isspace(c) || strchr("{}[]()<>=|/\\!?~'\",.;:#$%^&*", c));
2230 /* find first character of current word */
2231 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
2233 int i, c, last;
2235 /* return if at begin of file */
2236 if (edit->curs1 <= 0)
2237 return 0;
2239 c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
2240 /* return if not at end or in word */
2241 if (is_break_char(c))
2242 return 0;
2244 /* search start of word to be completed */
2245 for (i = 2;; i++) {
2246 /* return if at begin of file */
2247 if (edit->curs1 - i < 0)
2248 return 0;
2250 last = c;
2251 c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
2253 if (is_break_char(c)) {
2254 /* return if word starts with digit */
2255 if (isdigit (last))
2256 return 0;
2258 *word_start = edit->curs1 - (i - 1); /* start found */
2259 *word_len = i - 1;
2260 break;
2263 /* success */
2264 return 1;
2267 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2269 /* collect the possible completions */
2270 static int
2271 edit_collect_completions (WEdit *edit, long start, int word_len,
2272 char *match_expr, struct selection *compl,
2273 int *num)
2275 int max_len = 0, i, skip;
2276 gsize len = 0;
2277 GString *temp;
2278 mc_search_t *srch;
2280 srch = mc_search_new(match_expr, -1);
2281 if (srch == NULL)
2282 return 0;
2284 srch->search_type = MC_SEARCH_T_REGEX;
2285 srch->is_case_sentitive = TRUE;
2286 srch->search_fn = edit_search_cmd_callback;
2288 /* collect max MAX_WORD_COMPLETIONS completions */
2289 start--;
2290 while (*num < MAX_WORD_COMPLETIONS) {
2291 /* get next match */
2292 if (mc_search_run (srch, (void *) edit, start+1, edit->last_byte, &len) == FALSE)
2293 break;
2294 start = srch->normal_offset;
2296 /* add matched completion if not yet added */
2297 temp = g_string_new("");
2298 for (i = 0; i < len; i++){
2299 skip = edit_get_byte(edit, start+i);
2300 if (isspace(skip))
2301 continue;
2302 g_string_append_c (temp, skip);
2305 skip = 0;
2307 for (i = 0; i < *num; i++) {
2308 if (strncmp
2310 (char *) &compl[i].text[word_len],
2311 (char *) &temp->str[word_len],
2312 max (len, compl[i].len) - word_len
2313 ) == 0) {
2314 skip = 1;
2315 break; /* skip it, already added */
2318 if (skip) {
2319 g_string_free(temp, TRUE);
2320 continue;
2323 compl[*num].text = temp->str;
2324 compl[*num].len = temp->len;
2325 (*num)++;
2326 g_string_free(temp, FALSE);
2328 /* note the maximal length needed for the completion dialog */
2329 if (len > max_len)
2330 max_len = len;
2332 mc_search_free(srch);
2333 return max_len;
2337 * Complete current word using regular expression search
2338 * backwards beginning at the current cursor position.
2340 void
2341 edit_complete_word_cmd (WEdit *edit)
2343 int word_len = 0, i, num_compl = 0, max_len;
2344 long word_start = 0;
2345 unsigned char *bufpos;
2346 char *match_expr;
2347 struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
2349 /* search start of word to be completed */
2350 if (!edit_find_word_start (edit, &word_start, &word_len))
2351 return;
2353 /* prepare match expression */
2354 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2355 [word_start & M_EDIT_BUF_SIZE];
2357 match_expr = g_strdup_printf ("(^|\\s)%.*s[^\\s\\.=\\+\\{\\}\\[\\]\\(\\)\\\\\\!\\,<>\\?\\/@#\\$%%\\^&\\*\\~\\|\\\"'\\:\\;]+", word_len, bufpos);
2359 /* collect the possible completions */
2360 /* start search from begin to end of file */
2361 max_len =
2362 edit_collect_completions (edit, 0, word_len, match_expr,
2363 (struct selection *) &compl, &num_compl);
2365 if (num_compl > 0) {
2366 /* insert completed word if there is only one match */
2367 if (num_compl == 1) {
2368 for (i = word_len; i < compl[0].len; i++)
2369 edit_insert (edit, *(compl[0].text + i));
2371 /* more than one possible completion => ask the user */
2372 else {
2373 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2374 /* !!! pressed again the selection dialog pops up, but that !!! */
2375 /* !!! seems to require a further internal state !!! */
2376 /*tty_beep (); */
2378 /* let the user select the preferred completion */
2379 editcmd_dialog_completion_show (edit, max_len, word_len,
2380 (struct selection *) &compl,
2381 num_compl);
2385 g_free (match_expr);
2386 /* release memory before return */
2387 for (i = 0; i < num_compl; i++)
2388 g_free (compl[i].text);
2392 void
2393 edit_select_codepage_cmd (WEdit *edit)
2395 #ifdef HAVE_CHARSET
2396 if (do_select_codepage ()) {
2397 const char *cp_id;
2399 cp_id = get_codepage_id (source_codepage >= 0 ?
2400 source_codepage : display_codepage);
2402 if (cp_id != NULL)
2403 edit->utf8 = str_isutf8 (cp_id);
2406 edit->force = REDRAW_COMPLETELY;
2407 edit_refresh_cmd (edit);
2408 #endif
2411 void
2412 edit_insert_literal_cmd (WEdit *edit)
2414 int char_for_insertion =
2415 editcmd_dialog_raw_key_query (_(" Insert Literal "),
2416 _(" Press any key: "), 0);
2417 edit_execute_key_command (edit, -1,
2418 ascii_alpha_to_cntrl (char_for_insertion));
2421 void
2422 edit_execute_macro_cmd (WEdit *edit)
2424 int command =
2425 CK_Macro (editcmd_dialog_raw_key_query
2426 (_(" Execute Macro "), _(" Press macro hotkey: "),
2427 1));
2428 if (command == CK_Macro (0))
2429 command = CK_Insert_Char;
2431 edit_execute_key_command (edit, command, -1);
2434 void
2435 edit_begin_end_macro_cmd(WEdit *edit)
2437 int command;
2439 /* edit is a pointer to the widget */
2440 if (edit) {
2441 command =
2442 edit->macro_i <
2443 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
2444 edit_execute_key_command (edit, command, -1);
2449 edit_load_forward_cmd (WEdit *edit)
2451 if (edit->modified) {
2452 if (edit_query_dialog2
2453 (_("Warning"),
2454 _(" Current text was modified without a file save. \n"
2455 " Continue discards these changes. "), _("C&ontinue"),
2456 _("&Cancel"))) {
2457 edit->force |= REDRAW_COMPLETELY;
2458 return 0;
2461 if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
2462 if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
2463 return 1;
2465 edit_stack_iterator++;
2466 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2467 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2468 edit_history_moveto[edit_stack_iterator].line);
2469 return 0;
2470 } else {
2471 return 1;
2473 } else {
2474 return 1;
2479 edit_load_back_cmd (WEdit *edit)
2481 if (edit->modified) {
2482 if (edit_query_dialog2
2483 (_("Warning"),
2484 _(" Current text was modified without a file save. \n"
2485 " Continue discards these changes. "), _("C&ontinue"),
2486 _("&Cancel"))) {
2487 edit->force |= REDRAW_COMPLETELY;
2488 return 0;
2491 if ( edit_stack_iterator > 0 ) {
2492 edit_stack_iterator--;
2493 if ( edit_history_moveto[edit_stack_iterator].filename ) {
2494 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
2495 edit_history_moveto[edit_stack_iterator].line);
2496 return 0;
2497 } else {
2498 return 1;
2500 } else {
2501 return 1;
2505 void
2506 edit_get_match_keyword_cmd (WEdit *edit)
2508 int word_len = 0;
2509 int num_def = 0;
2510 int max_len = 0;
2511 int i;
2512 long word_start = 0;
2513 unsigned char *bufpos;
2514 char *match_expr;
2515 char *path = NULL;
2516 char *ptr = NULL;
2517 char *tagfile = NULL;
2519 etags_hash_t def_hash[MAX_DEFINITIONS];
2521 for ( i = 0; i < MAX_DEFINITIONS; i++) {
2522 def_hash[i].filename = NULL;
2525 /* search start of word to be completed */
2526 if (!edit_find_word_start (edit, &word_start, &word_len))
2527 return;
2529 /* prepare match expression */
2530 bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
2531 [word_start & M_EDIT_BUF_SIZE];
2532 match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
2534 ptr = g_get_current_dir ();
2535 path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
2536 g_free (ptr);
2538 /* Recursive search file 'TAGS' in parent dirs */
2539 do {
2540 ptr = g_path_get_dirname (path);
2541 g_free(path); path = ptr;
2542 g_free (tagfile);
2543 tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
2544 if ( exist_file (tagfile) )
2545 break;
2546 } while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
2548 if (tagfile){
2549 num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
2550 g_free (tagfile);
2552 g_free (path);
2554 max_len = MAX_WIDTH_DEF_DIALOG;
2555 word_len = 0;
2556 if ( num_def > 0 ) {
2557 editcmd_dialog_select_definition_show (edit, match_expr, max_len, word_len,
2558 (etags_hash_t *) &def_hash,
2559 num_def);
2561 g_free (match_expr);
2564 void
2565 edit_move_block_to_right (WEdit * edit)
2567 long start_mark, end_mark;
2568 long cur_bol, start_bol;
2570 if ( eval_marks (edit, &start_mark, &end_mark) )
2571 return;
2573 start_bol = edit_bol (edit, start_mark);
2574 cur_bol = edit_bol (edit, end_mark - 1);
2575 do {
2576 edit_cursor_move (edit, cur_bol - edit->curs1);
2577 if ( option_fill_tabs_with_spaces ) {
2578 if ( option_fake_half_tabs ) {
2579 insert_spaces_tab (edit, 1);
2580 } else {
2581 insert_spaces_tab (edit, 0);
2583 } else {
2584 edit_insert (edit, '\t');
2586 edit_cursor_move (edit, edit_bol (edit, cur_bol) - edit->curs1);
2587 if ( cur_bol == 0 ) {
2588 break;
2590 cur_bol = edit_bol (edit, cur_bol - 1);
2591 } while (cur_bol >= start_bol) ;
2592 edit->force |= REDRAW_PAGE;
2595 void
2596 edit_move_block_to_left (WEdit * edit)
2598 long start_mark, end_mark;
2599 long cur_bol, start_bol;
2600 int i, del_tab_width;
2601 int next_char;
2603 if ( eval_marks (edit, &start_mark, &end_mark) )
2604 return;
2606 start_bol = edit_bol (edit, start_mark);
2607 cur_bol = edit_bol (edit, end_mark - 1);
2608 do {
2609 edit_cursor_move (edit, cur_bol - edit->curs1);
2610 if (option_fake_half_tabs) {
2611 del_tab_width = HALF_TAB_SIZE;
2612 } else {
2613 del_tab_width = option_tab_spacing;
2615 next_char = edit_get_byte (edit, edit->curs1);
2616 if ( next_char == '\t' ) {
2617 edit_delete (edit, 1);
2618 } else if ( next_char == ' ' ) {
2619 for (i = 1; i <= del_tab_width; i++) {
2620 if ( next_char == ' ' ) {
2621 edit_delete (edit, 1);
2623 next_char = edit_get_byte (edit, edit->curs1);
2626 if ( cur_bol == 0 ) {
2627 break;
2629 cur_bol = edit_bol (edit, cur_bol - 1);
2630 } while (cur_bol >= start_bol) ;
2631 edit->force |= REDRAW_PAGE;