FIX: Completion in editor doesn't work with subwords ended with '_'
[midnight-commander.git] / edit / editcmd.c
blob05e44570abc29d87b0d0d59b3b62e9c5a35bce02
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"
49 #include "../src/history.h"
51 #include "../src/tty.h" /* LINES */
52 #include "../src/widget.h" /* listbox_new() */
53 #include "../src/layout.h" /* clr_scr() */
54 #include "../src/main.h" /* mc_home source_codepage */
55 #include "../src/help.h" /* interactive_display() */
56 #include "../src/key.h" /* XCTRL */
57 #include "../src/wtools.h" /* message() */
58 #include "../src/charsets.h"
59 #include "../src/selcodepage.h"
60 #include "../src/strutil.h" /* utf string functions */
62 #include "../edit/edit-impl.h"
63 #include "../edit/edit.h"
64 #include "../edit/editlock.h"
65 #include "../edit/editcmddef.h"
66 #include "../edit/edit-widget.h"
67 #include "../edit/editcmd_dialogs.h"
68 #include "../edit/etags.h"
70 /* globals: */
72 /* search and replace: */
73 static int search_create_bookmark = 0;
74 /* static int search_in_all_charsets = 0; */
76 /* queries on a save */
77 int edit_confirm_save = 1;
79 static int edit_save_cmd (WEdit *edit);
80 static unsigned char *edit_get_block (WEdit *edit, long start,
81 long finish, int *l);
83 static void
84 edit_search_cmd_search_create_bookmark(WEdit * edit)
86 int found = 0, books = 0;
87 int l = 0, l_last = -1;
88 long q = 0;
89 gsize len = 0;
91 for (;;) {
92 if (!mc_search_run(edit->search, (void *) edit, q, edit->last_byte, &len))
93 break;
95 found++;
96 l += edit_count_lines (edit, q, edit->search->normal_offset);
97 if (l != l_last) {
98 book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
99 books++;
101 l_last = l;
102 q = edit->search->normal_offset + 1;
105 if (found) {
106 /* in response to number of bookmarks added because of string being found %d times */
107 message (D_NORMAL, _("Search"), _(" %d items found, %d bookmarks added "), found, books);
108 } else {
109 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
113 static int
114 edit_search_cmd_callback(const void *user_data, gsize char_offset)
116 return edit_get_byte ((WEdit * )user_data, (long) char_offset);
119 void edit_help_cmd (WEdit * edit)
121 interactive_display (NULL, "[Internal File Editor]");
122 edit->force |= REDRAW_COMPLETELY;
125 void edit_refresh_cmd (WEdit * edit)
127 #ifndef HAVE_SLANG
128 clr_scr();
129 do_refresh();
130 #else
132 int color;
133 edit_get_syntax_color (edit, -1, &color);
135 touchwin(stdscr);
136 #endif /* !HAVE_SLANG */
137 mc_refresh();
138 doupdate();
141 /* If 0 (quick save) then a) create/truncate <filename> file,
142 b) save to <filename>;
143 if 1 (safe save) then a) save to <tempnam>,
144 b) rename <tempnam> to <filename>;
145 if 2 (do backups) then a) save to <tempnam>,
146 b) rename <filename> to <filename.backup_ext>,
147 c) rename <tempnam> to <filename>. */
149 /* returns 0 on error, -1 on abort */
150 static int
151 edit_save_file (WEdit *edit, const char *filename)
153 char *p;
154 gchar *tmp;
155 long filelen = 0;
156 char *savename = 0;
157 gchar *real_filename;
158 int this_save_mode, fd = -1;
160 if (!filename)
161 return 0;
162 if (!*filename)
163 return 0;
165 if (*filename != PATH_SEP && edit->dir) {
166 real_filename = concat_dir_and_file (edit->dir, filename);
167 } else {
168 real_filename = g_strdup(filename);
171 this_save_mode = option_save_mode;
172 if (this_save_mode != EDIT_QUICK_SAVE) {
173 if (!vfs_file_is_local (real_filename) ||
174 (fd = mc_open (real_filename, O_RDONLY | O_BINARY)) == -1) {
176 * The file does not exists yet, so no safe save or
177 * backup are necessary.
179 this_save_mode = EDIT_QUICK_SAVE;
181 if (fd != -1)
182 mc_close (fd);
185 if (this_save_mode == EDIT_QUICK_SAVE &&
186 !edit->skip_detach_prompt) {
187 int rv;
188 struct stat sb;
190 rv = mc_stat (real_filename, &sb);
191 if (rv == 0 && sb.st_nlink > 1) {
192 rv = edit_query_dialog3 (_("Warning"),
193 _(" File has hard-links. Detach before saving? "),
194 _("&Yes"), _("&No"), _("&Cancel"));
195 switch (rv) {
196 case 0:
197 this_save_mode = EDIT_SAFE_SAVE;
198 /* fallthrough */
199 case 1:
200 edit->skip_detach_prompt = 1;
201 break;
202 default:
203 g_free(real_filename);
204 return -1;
208 /* Prevent overwriting changes from other editor sessions. */
209 if (rv == 0 && edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime) {
211 /* The default action is "Cancel". */
212 query_set_sel(1);
214 rv = edit_query_dialog2 (
215 _("Warning"),
216 _("The file has been modified in the meantime. Save anyway?"),
217 _("&Yes"),
218 _("&Cancel"));
219 if (rv != 0){
220 g_free(real_filename);
221 return -1;
226 if (this_save_mode != EDIT_QUICK_SAVE) {
227 char *savedir, *saveprefix;
228 const char *slashpos;
229 slashpos = strrchr (real_filename, PATH_SEP);
230 if (slashpos) {
231 savedir = g_strdup (real_filename);
232 savedir[slashpos - real_filename + 1] = '\0';
233 } else
234 savedir = g_strdup (".");
235 saveprefix = concat_dir_and_file (savedir, "cooledit");
236 g_free (savedir);
237 fd = mc_mkstemps (&savename, saveprefix, NULL);
238 g_free (saveprefix);
239 if (!savename){
240 g_free(real_filename);
241 return 0;
243 /* FIXME:
244 * Close for now because mc_mkstemps use pure open system call
245 * to create temporary file and it needs to be reopened by
246 * VFS-aware mc_open().
248 close (fd);
249 } else
250 savename = g_strdup (real_filename);
252 mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
253 mc_chmod (savename, edit->stat1.st_mode);
255 if ((fd =
256 mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
257 edit->stat1.st_mode)) == -1)
258 goto error_save;
260 /* pipe save */
261 if ((p = edit_get_write_filter (savename, real_filename))) {
262 FILE *file;
264 mc_close (fd);
265 file = (FILE *) popen (p, "w");
267 if (file) {
268 filelen = edit_write_stream (edit, file);
269 #if 1
270 pclose (file);
271 #else
272 if (pclose (file) != 0) {
273 tmp = g_strconcat (_(" Error writing to pipe: "),
274 p, " ", (char *) NULL);
275 edit_error_dialog (_("Error"), tmp);
276 g_free(tmp);
277 g_free (p);
278 goto error_save;
280 #endif
281 } else {
282 tmp = g_strconcat (_(" Cannot open pipe for writing: "),
283 p, " ", (char *) NULL);
285 edit_error_dialog (_("Error"),
286 get_sys_error (tmp));
287 g_free (p);
288 g_free(tmp);
289 goto error_save;
291 g_free (p);
292 } else {
293 long buf;
294 buf = 0;
295 filelen = edit->last_byte;
296 while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
297 if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
298 != EDIT_BUF_SIZE) {
299 mc_close (fd);
300 goto error_save;
302 buf++;
304 if (mc_write
305 (fd, (char *) edit->buffers1[buf],
306 edit->curs1 & M_EDIT_BUF_SIZE) !=
307 (edit->curs1 & M_EDIT_BUF_SIZE)) {
308 filelen = -1;
309 } else if (edit->curs2) {
310 edit->curs2--;
311 buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
312 if (mc_write
313 (fd,
314 (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
315 (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
316 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
317 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
318 filelen = -1;
319 } else {
320 while (--buf >= 0) {
321 if (mc_write
322 (fd, (char *) edit->buffers2[buf],
323 EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
324 filelen = -1;
325 break;
329 edit->curs2++;
331 if (mc_close (fd))
332 goto error_save;
334 /* Update the file information, especially the mtime. */
335 if (mc_stat (savename, &edit->stat1) == -1)
336 goto error_save;
339 if (filelen != edit->last_byte)
340 goto error_save;
342 if (this_save_mode == EDIT_DO_BACKUP) {
343 assert (option_backup_ext != NULL);
344 tmp = g_strconcat (real_filename, option_backup_ext,(char *) NULL);
345 if (mc_rename (real_filename, tmp) == -1){
346 g_free(tmp);
347 goto error_save;
351 if (this_save_mode != EDIT_QUICK_SAVE)
352 if (mc_rename (savename, real_filename) == -1)
353 goto error_save;
354 g_free (savename);
355 g_free(real_filename);
356 return 1;
357 error_save:
358 /* FIXME: Is this safe ?
359 * if (this_save_mode != EDIT_QUICK_SAVE)
360 * mc_unlink (savename);
362 g_free(real_filename);
363 g_free (savename);
364 return 0;
367 void menu_save_mode_cmd (void)
369 #define DLG_X 38
370 #define DLG_Y 10
371 static char *str_result;
372 static int save_mode_new;
373 static const char *str[] =
375 N_("Quick save "),
376 N_("Safe save "),
377 N_("Do backups -->")};
379 static QuickWidget widgets[] =
381 {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
382 B_CANCEL, 0, 0, NULL, NULL, NULL},
383 {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
384 B_ENTER, 0, 0, NULL, NULL, NULL},
385 {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
386 0, 0, &str_result, "edit-backup-ext", NULL, NULL},
387 {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
388 0, 0, 0, NULL, NULL, NULL},
389 {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
390 0, &save_mode_new, (char **) str, NULL, NULL, NULL},
391 NULL_QuickWidget};
392 static QuickDialog dialog =
393 {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
394 widgets, 0};
395 static int i18n_flag = 0;
397 if (!i18n_flag) {
398 size_t i;
399 size_t maxlen = 0;
400 int dlg_x;
401 size_t l1;
403 /* OK/Cancel buttons */
404 l1 = str_term_width1 (_(widgets[0].text)) + str_term_width1 (_(widgets[1].text)) + 5;
405 maxlen = max (maxlen, l1);
407 for (i = 0; i < 3; i++ ) {
408 str[i] = _(str[i]);
409 maxlen = max (maxlen, (size_t) str_term_width1 (str[i]) + 7);
411 i18n_flag = 1;
413 dlg_x = maxlen + str_term_width1 (_(widgets[3].text)) + 5 + 1;
414 widgets[2].hotkey_pos = str_term_width1 (_(widgets[3].text)); /* input field length */
415 dlg_x = min (COLS, dlg_x);
416 dialog.xlen = dlg_x;
418 i = (dlg_x - l1)/3;
419 widgets[1].relative_x = i;
420 widgets[0].relative_x = i + str_term_width1 (_(widgets[1].text)) + i + 4;
422 widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
424 for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
425 widgets[i].x_divisions = dlg_x;
428 assert (option_backup_ext != NULL);
429 widgets[2].text = option_backup_ext;
430 widgets[4].value = option_save_mode;
431 if (quick_dialog (&dialog) != B_ENTER)
432 return;
433 option_save_mode = save_mode_new;
435 g_free (option_backup_ext);
436 option_backup_ext = str_result;
437 str_result = NULL;
440 void
441 edit_set_filename (WEdit *edit, const char *f)
443 g_free (edit->filename);
444 if (!f)
445 f = "";
446 edit->filename = g_strdup (f);
447 if (edit->dir == NULL && *f != PATH_SEP)
448 #ifdef USE_VFS
449 edit->dir = g_strdup (vfs_get_current_dir ());
450 #else
451 edit->dir = g_get_current_dir ();
452 #endif
455 /* Here we want to warn the users of overwriting an existing file,
456 but only if they have made a change to the filename */
457 /* returns 1 on success */
459 edit_save_as_cmd (WEdit *edit)
461 /* This heads the 'Save As' dialog box */
462 char *exp;
463 int save_lock = 0;
464 int different_filename = 0;
466 exp = input_expand_dialog (
467 _(" Save As "), _(" Enter file name: "),MC_HISTORY_EDIT_SAVE_AS, edit->filename);
468 edit_push_action (edit, KEY_PRESS + edit->start_display);
470 if (exp) {
471 if (!*exp) {
472 g_free (exp);
473 edit->force |= REDRAW_COMPLETELY;
474 return 0;
475 } else {
476 int rv;
477 if (strcmp (edit->filename, exp)) {
478 int file;
479 different_filename = 1;
480 if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
481 /* the file exists */
482 mc_close (file);
483 /* Overwrite the current file or cancel the operation */
484 if (edit_query_dialog2
485 (_("Warning"),
486 _(" A file already exists with this name. "),
487 _("&Overwrite"), _("&Cancel"))) {
488 edit->force |= REDRAW_COMPLETELY;
489 g_free (exp);
490 return 0;
493 save_lock = edit_lock_file (exp);
494 } else {
495 /* filenames equal, check if already locked */
496 if (!edit->locked && !edit->delete_file)
497 save_lock = edit_lock_file (exp);
500 rv = edit_save_file (edit, exp);
501 switch (rv) {
502 case 1:
503 /* Succesful, so unlock both files */
504 if (different_filename) {
505 if (save_lock)
506 edit_unlock_file (exp);
507 if (edit->locked)
508 edit->locked = edit_unlock_file (edit->filename);
509 } else {
510 if (edit->locked || save_lock)
511 edit->locked = edit_unlock_file (edit->filename);
514 edit_set_filename (edit, exp);
515 g_free (exp);
516 edit->modified = 0;
517 edit->delete_file = 0;
518 if (different_filename)
519 edit_load_syntax (edit, NULL, option_syntax_type);
520 edit->force |= REDRAW_COMPLETELY;
521 return 1;
522 default:
523 edit_error_dialog (_(" Save As "),
524 get_sys_error (_
525 (" Cannot save file. ")));
526 /* fallthrough */
527 case -1:
528 /* Failed, so maintain modify (not save) lock */
529 if (save_lock)
530 edit_unlock_file (exp);
531 g_free (exp);
532 edit->force |= REDRAW_COMPLETELY;
533 return 0;
537 edit->force |= REDRAW_COMPLETELY;
538 return 0;
541 /* {{{ Macro stuff starts here */
543 /* creates a macro file if it doesn't exist */
544 static FILE *edit_open_macro_file (const char *r)
546 gchar *filename;
547 FILE *fd;
548 int file;
549 filename = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
550 if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1){
551 g_free(filename);
552 return 0;
554 close (file);
555 fd = fopen (filename, r);
556 g_free(filename);
557 return fd;
560 #define MAX_MACROS 1024
561 static int saved_macro[MAX_MACROS + 1];
562 static int saved_macros_loaded = 0;
565 This is just to stop the macro file be loaded over and over for keys
566 that aren't defined to anything. On slow systems this could be annoying.
568 static int
569 macro_exists (int k)
571 int i;
572 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
573 if (saved_macro[i] == k)
574 return i;
575 return -1;
578 /* returns 1 on error */
579 static int
580 edit_delete_macro (WEdit * edit, int k)
582 gchar *tmp, *tmp2;
583 struct macro macro[MAX_MACRO_LENGTH];
584 FILE *f, *g;
585 int s, i, n, j = 0;
587 (void) edit;
589 if (saved_macros_loaded)
590 if ((j = macro_exists (k)) < 0)
591 return 0;
592 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
593 g = fopen (tmp , "w");
594 g_free(tmp);
595 if (!g) {
596 edit_error_dialog (_(" Delete macro "),
597 get_sys_error (_(" Cannot open temp file ")));
598 return 1;
600 f = edit_open_macro_file ("r");
601 if (!f) {
602 edit_error_dialog (_(" Delete macro "),
603 get_sys_error (_(" Cannot open macro file ")));
604 fclose (g);
605 return 1;
607 for (;;) {
608 n = fscanf (f, ("key '%d 0': "), &s);
609 if (!n || n == EOF)
610 break;
611 n = 0;
612 while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
613 n++;
614 fscanf (f, ";\n");
615 if (s != k) {
616 fprintf (g, ("key '%d 0': "), s);
617 for (i = 0; i < n; i++)
618 fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
619 fprintf (g, ";\n");
622 fclose (f);
623 fclose (g);
624 tmp = concat_dir_and_file (home_dir, EDIT_TEMP_FILE);
625 tmp2 = concat_dir_and_file (home_dir, EDIT_MACRO_FILE);
626 if (rename ( tmp, tmp2) == -1) {
627 edit_error_dialog (_(" Delete macro "),
628 get_sys_error (_(" Cannot overwrite macro file ")));
629 g_free(tmp);
630 g_free(tmp2);
631 return 1;
633 g_free(tmp);
634 g_free(tmp2);
636 if (saved_macros_loaded)
637 memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
638 return 0;
641 /* returns 0 on error */
642 int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
644 FILE *f;
645 int s, i;
647 edit_push_action (edit, KEY_PRESS + edit->start_display);
648 s = editcmd_dialog_raw_key_query (_(" Save macro "),
649 _(" Press the macro's new hotkey: "), 1);
650 edit->force |= REDRAW_COMPLETELY;
651 if (s) {
652 if (edit_delete_macro (edit, s))
653 return 0;
654 f = edit_open_macro_file ("a+");
655 if (f) {
656 fprintf (f, ("key '%d 0': "), s);
657 for (i = 0; i < n; i++)
658 fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
659 fprintf (f, ";\n");
660 fclose (f);
661 if (saved_macros_loaded) {
662 for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
663 saved_macro[i] = s;
665 return 1;
666 } else
667 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
669 return 0;
672 void edit_delete_macro_cmd (WEdit * edit)
674 int command;
676 command = editcmd_dialog_raw_key_query (_ (" Delete macro "),
677 _ (" Press macro hotkey: "), 1);
679 if (!command)
680 return;
682 edit_delete_macro (edit, command);
685 /* return 0 on error */
686 int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
688 FILE *f;
689 int s, i = 0, found = 0;
691 (void) edit;
693 if (saved_macros_loaded)
694 if (macro_exists (k) < 0)
695 return 0;
697 if ((f = edit_open_macro_file ("r"))) {
698 struct macro dummy;
699 do {
700 int u;
701 u = fscanf (f, ("key '%d 0': "), &s);
702 if (!u || u == EOF)
703 break;
704 if (!saved_macros_loaded)
705 saved_macro[i++] = s;
706 if (!found) {
707 *n = 0;
708 while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
709 (*n)++;
710 } else {
711 while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
713 fscanf (f, ";\n");
714 if (s == k)
715 found = 1;
716 } while (!found || !saved_macros_loaded);
717 if (!saved_macros_loaded) {
718 saved_macro[i] = 0;
719 saved_macros_loaded = 1;
721 fclose (f);
722 return found;
723 } else
724 edit_error_dialog (_(" Load macro "),
725 get_sys_error (_(" Cannot open macro file ")));
726 return 0;
729 /* }}} Macro stuff starts here */
731 /* returns 1 on success */
732 int edit_save_confirm_cmd (WEdit * edit)
734 gchar *f = NULL;
736 if (edit_confirm_save) {
737 f = g_strconcat (_(" Confirm save file? : "), edit->filename, " ", NULL);
738 if (edit_query_dialog2 (_(" Save file "), f, _("&Save"), _("&Cancel"))){
739 g_free(f);
740 return 0;
742 g_free(f);
744 return edit_save_cmd (edit);
748 /* returns 1 on success */
749 static int
750 edit_save_cmd (WEdit *edit)
752 int res, save_lock = 0;
754 if (!edit->locked && !edit->delete_file)
755 save_lock = edit_lock_file (edit->filename);
756 res = edit_save_file (edit, edit->filename);
758 /* Maintain modify (not save) lock on failure */
759 if ((res > 0 && edit->locked) || save_lock)
760 edit->locked = edit_unlock_file (edit->filename);
762 /* On failure try 'save as', it does locking on its own */
763 if (!res)
764 return edit_save_as_cmd (edit);
765 edit->force |= REDRAW_COMPLETELY;
766 if (res > 0) {
767 edit->delete_file = 0;
768 edit->modified = 0;
771 return 1;
775 /* returns 1 on success */
776 int edit_new_cmd (WEdit * edit)
778 if (edit->modified) {
779 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("C&ontinue"), _ ("&Cancel"))) {
780 edit->force |= REDRAW_COMPLETELY;
781 return 0;
784 edit->force |= REDRAW_COMPLETELY;
786 return edit_renew (edit); /* if this gives an error, something has really screwed up */
789 /* returns 1 on error */
790 static int
791 edit_load_file_from_filename (WEdit * edit, char *exp)
793 int prev_locked = edit->locked;
794 char *prev_filename = g_strdup (edit->filename);
796 if (!edit_reload (edit, exp)) {
797 g_free (prev_filename);
798 return 1;
801 if (prev_locked)
802 edit_unlock_file (prev_filename);
803 g_free (prev_filename);
804 return 0;
807 static void
808 edit_load_syntax_file (WEdit * edit)
810 char *extdir;
811 int dir = 0;
813 if (geteuid () == 0) {
814 dir = query_dialog (_("Syntax file edit"),
815 _(" Which syntax file you want to edit? "), D_NORMAL, 2,
816 _("&User"), _("&System Wide"));
819 extdir = concat_dir_and_file (mc_home, "syntax" PATH_SEP_STR "Syntax");
820 if (!exist_file(extdir)) {
821 g_free (extdir);
822 extdir = concat_dir_and_file (mc_home_alt, "syntax" PATH_SEP_STR "Syntax");
825 if (dir == 0) {
826 char *buffer;
828 buffer = concat_dir_and_file (home_dir, EDIT_SYNTAX_FILE);
829 check_for_default (extdir, buffer);
830 edit_load_file_from_filename (edit, buffer);
831 g_free (buffer);
832 } else if (dir == 1)
833 edit_load_file_from_filename (edit, extdir);
835 g_free (extdir);
838 static void
839 edit_load_menu_file (WEdit * edit)
841 char *buffer;
842 char *menufile;
843 int dir = 0;
845 dir = query_dialog (
846 _(" Menu edit "),
847 _(" Which menu file do you want to edit? "), D_NORMAL,
848 geteuid() ? 2 : 3, _("&Local"), _("&User"), _("&System Wide")
851 menufile = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
853 if (!exist_file (menufile)) {
854 g_free (menufile);
855 menufile = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
858 switch (dir) {
859 case 0:
860 buffer = g_strdup (EDIT_LOCAL_MENU);
861 check_for_default (menufile, buffer);
862 chmod (buffer, 0600);
863 break;
865 case 1:
866 buffer = concat_dir_and_file (home_dir, EDIT_HOME_MENU);
867 check_for_default (menufile, buffer);
868 break;
870 case 2:
871 buffer = concat_dir_and_file (mc_home, EDIT_GLOBAL_MENU);
872 if (!exist_file (buffer)) {
873 g_free (buffer);
874 buffer = concat_dir_and_file (mc_home_alt, EDIT_GLOBAL_MENU);
876 break;
878 default:
879 g_free (menufile);
880 return;
883 edit_load_file_from_filename (edit, buffer);
885 g_free (buffer);
886 g_free (menufile);
890 edit_load_cmd (WEdit *edit, edit_current_file_t what)
892 char *exp;
894 if (edit->modified
895 && (edit_query_dialog2
896 (_("Warning"),
897 _(" Current text was modified without a file save. \n"
898 " Continue discards these changes. "),
899 _("C&ontinue"), _("&Cancel")) == 1)) {
900 edit->force |= REDRAW_COMPLETELY;
901 return 0;
904 switch (what) {
905 case EDIT_FILE_COMMON:
906 exp = input_expand_dialog (_(" Load "), _(" Enter file name: "),
907 MC_HISTORY_EDIT_LOAD, edit->filename);
909 if (exp) {
910 if (*exp)
911 edit_load_file_from_filename (edit, exp);
912 g_free (exp);
914 break;
916 case EDIT_FILE_SYNTAX:
917 edit_load_syntax_file (edit);
918 break;
920 case EDIT_FILE_MENU:
921 edit_load_menu_file (edit);
922 break;
924 default:
925 break;
928 edit->force |= REDRAW_COMPLETELY;
929 return 0;
933 if mark2 is -1 then marking is from mark1 to the cursor.
934 Otherwise its between the markers. This handles this.
935 Returns 1 if no text is marked.
937 int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
939 if (edit->mark1 != edit->mark2) {
940 if (edit->mark2 >= 0) {
941 *start_mark = min (edit->mark1, edit->mark2);
942 *end_mark = max (edit->mark1, edit->mark2);
943 } else {
944 *start_mark = min (edit->mark1, edit->curs1);
945 *end_mark = max (edit->mark1, edit->curs1);
946 edit->column2 = edit->curs_col;
948 return 0;
949 } else {
950 *start_mark = *end_mark = 0;
951 edit->column2 = edit->column1 = 0;
952 return 1;
956 #define space_width 1
958 void
959 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
961 long cursor;
962 int i, col;
963 cursor = edit->curs1;
964 col = edit_get_col (edit);
965 for (i = 0; i < size; i++) {
966 if (data[i] == '\n') { /* fill in and move to next line */
967 int l;
968 long p;
969 if (edit_get_byte (edit, edit->curs1) != '\n') {
970 l = width - (edit_get_col (edit) - col);
971 while (l > 0) {
972 edit_insert (edit, ' ');
973 l -= space_width;
976 for (p = edit->curs1;; p++) {
977 if (p == edit->last_byte) {
978 edit_cursor_move (edit, edit->last_byte - edit->curs1);
979 edit_insert_ahead (edit, '\n');
980 p++;
981 break;
983 if (edit_get_byte (edit, p) == '\n') {
984 p++;
985 break;
988 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
989 l = col - edit_get_col (edit);
990 while (l >= space_width) {
991 edit_insert (edit, ' ');
992 l -= space_width;
994 continue;
996 edit_insert (edit, data[i]);
998 edit_cursor_move (edit, cursor - edit->curs1);
1001 #define TEMP_BUF_LEN 1024
1004 edit_insert_column_of_text_from_file (WEdit * edit, int file)
1006 long cursor;
1007 int i, col;
1008 int blocklen = -1, width;
1009 unsigned char *data;
1010 cursor = edit->curs1;
1011 col = edit_get_col (edit);
1012 data = g_malloc (TEMP_BUF_LEN);
1013 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0) {
1014 for (width = 0; width < blocklen; width++) {
1015 if (data[width] == '\n')
1016 break;
1018 for (i = 0; i < blocklen; i++) {
1019 if (data[i] == '\n') { /* fill in and move to next line */
1020 int l;
1021 long p;
1022 if (edit_get_byte (edit, edit->curs1) != '\n') {
1023 l = width - (edit_get_col (edit) - col);
1024 while (l > 0) {
1025 edit_insert (edit, ' ');
1026 l -= space_width;
1029 for (p = edit->curs1;; p++) {
1030 if (p == edit->last_byte) {
1031 edit_cursor_move (edit, edit->last_byte - edit->curs1);
1032 edit_insert_ahead (edit, '\n');
1033 p++;
1034 break;
1036 if (edit_get_byte (edit, p) == '\n') {
1037 p++;
1038 break;
1041 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
1042 l = col - edit_get_col (edit);
1043 while (l >= space_width) {
1044 edit_insert (edit, ' ');
1045 l -= space_width;
1047 continue;
1049 edit_insert (edit, data[i]);
1052 edit_cursor_move (edit, cursor - edit->curs1);
1053 g_free(data);
1054 edit->force |= REDRAW_PAGE;
1055 return blocklen;
1058 void
1059 edit_block_copy_cmd (WEdit *edit)
1061 long start_mark, end_mark, current = edit->curs1;
1062 int size;
1063 unsigned char *copy_buf;
1065 edit_update_curs_col (edit);
1066 if (eval_marks (edit, &start_mark, &end_mark))
1067 return;
1069 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1071 /* all that gets pushed are deletes hence little space is used on the stack */
1073 edit_push_markers (edit);
1075 if (column_highlighting) {
1076 edit_insert_column_of_text (edit, copy_buf, size,
1077 abs (edit->column2 - edit->column1));
1078 } else {
1079 while (size--)
1080 edit_insert_ahead (edit, copy_buf[size]);
1083 g_free (copy_buf);
1084 edit_scroll_screen_over_cursor (edit);
1086 if (column_highlighting) {
1087 edit_set_markers (edit, 0, 0, 0, 0);
1088 edit_push_action (edit, COLUMN_ON);
1089 column_highlighting = 0;
1090 } else if (start_mark < current && end_mark > current)
1091 edit_set_markers (edit, start_mark,
1092 end_mark + end_mark - start_mark, 0, 0);
1094 edit->force |= REDRAW_PAGE;
1098 void
1099 edit_block_move_cmd (WEdit *edit)
1101 long count;
1102 long current;
1103 unsigned char *copy_buf;
1104 long start_mark, end_mark;
1105 int deleted = 0;
1106 int x = 0;
1108 if (eval_marks (edit, &start_mark, &end_mark))
1109 return;
1110 if (column_highlighting) {
1111 edit_update_curs_col (edit);
1112 x = edit->curs_col;
1113 if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1114 if ((x > edit->column1 && x < edit->column2)
1115 || (x > edit->column2 && x < edit->column1))
1116 return;
1117 } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
1118 return;
1120 if ((end_mark - start_mark) > option_max_undo / 2)
1121 if (edit_query_dialog2
1122 (_("Warning"),
1124 (" Block is large, you may not be able to undo this action. "),
1125 _("C&ontinue"), _("&Cancel")))
1126 return;
1128 edit_push_markers (edit);
1129 current = edit->curs1;
1130 if (column_highlighting) {
1131 int size, c1, c2, line;
1132 line = edit->curs_line;
1133 if (edit->mark2 < 0)
1134 edit_mark_cmd (edit, 0);
1135 c1 = min (edit->column1, edit->column2);
1136 c2 = max (edit->column1, edit->column2);
1137 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1138 if (x < c2) {
1139 edit_block_delete_cmd (edit);
1140 deleted = 1;
1142 edit_move_to_line (edit, line);
1143 edit_cursor_move (edit,
1144 edit_move_forward3 (edit,
1145 edit_bol (edit, edit->curs1),
1146 x, 0) - edit->curs1);
1147 edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
1148 if (!deleted) {
1149 line = edit->curs_line;
1150 edit_update_curs_col (edit);
1151 x = edit->curs_col;
1152 edit_block_delete_cmd (edit);
1153 edit_move_to_line (edit, line);
1154 edit_cursor_move (edit,
1155 edit_move_forward3 (edit,
1156 edit_bol (edit,
1157 edit->curs1),
1158 x, 0) - edit->curs1);
1160 edit_set_markers (edit, 0, 0, 0, 0);
1161 edit_push_action (edit, COLUMN_ON);
1162 column_highlighting = 0;
1163 } else {
1164 copy_buf = g_malloc (end_mark - start_mark);
1165 edit_cursor_move (edit, start_mark - edit->curs1);
1166 edit_scroll_screen_over_cursor (edit);
1167 count = start_mark;
1168 while (count < end_mark) {
1169 copy_buf[end_mark - count - 1] = edit_delete (edit, 1);
1170 count++;
1172 edit_scroll_screen_over_cursor (edit);
1173 edit_cursor_move (edit,
1174 current - edit->curs1 -
1175 (((current - edit->curs1) >
1176 0) ? end_mark - start_mark : 0));
1177 edit_scroll_screen_over_cursor (edit);
1178 while (count-- > start_mark)
1179 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1180 edit_set_markers (edit, edit->curs1,
1181 edit->curs1 + end_mark - start_mark, 0, 0);
1183 edit_scroll_screen_over_cursor (edit);
1184 g_free (copy_buf);
1185 edit->force |= REDRAW_PAGE;
1188 static void
1189 edit_delete_column_of_text (WEdit * edit)
1191 long p, q, r, m1, m2;
1192 int b, c, d;
1193 int n;
1195 eval_marks (edit, &m1, &m2);
1196 n = edit_move_forward (edit, m1, 0, m2) + 1;
1197 c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
1198 d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
1200 b = min (c, d);
1201 c = max (c, d);
1203 while (n--) {
1204 r = edit_bol (edit, edit->curs1);
1205 p = edit_move_forward3 (edit, r, b, 0);
1206 q = edit_move_forward3 (edit, r, c, 0);
1207 if (p < m1)
1208 p = m1;
1209 if (q > m2)
1210 q = m2;
1211 edit_cursor_move (edit, p - edit->curs1);
1212 while (q > p) { /* delete line between margins */
1213 if (edit_get_byte (edit, edit->curs1) != '\n')
1214 edit_delete (edit, 1);
1215 q--;
1217 if (n) /* move to next line except on the last delete */
1218 edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
1222 /* if success return 0 */
1223 static int
1224 edit_block_delete (WEdit *edit)
1226 long count;
1227 long start_mark, end_mark;
1228 if (eval_marks (edit, &start_mark, &end_mark))
1229 return 0;
1230 if (column_highlighting && edit->mark2 < 0)
1231 edit_mark_cmd (edit, 0);
1232 if ((end_mark - start_mark) > option_max_undo / 2) {
1233 /* Warning message with a query to continue or cancel the operation */
1234 if (edit_query_dialog2
1235 (_("Warning"),
1237 (" Block is large, you may not be able to undo this action. "),
1238 _("C&ontinue"), _("&Cancel"))) {
1239 return 1;
1242 edit_push_markers (edit);
1243 edit_cursor_move (edit, start_mark - edit->curs1);
1244 edit_scroll_screen_over_cursor (edit);
1245 count = start_mark;
1246 if (start_mark < end_mark) {
1247 if (column_highlighting) {
1248 if (edit->mark2 < 0)
1249 edit_mark_cmd (edit, 0);
1250 edit_delete_column_of_text (edit);
1251 } else {
1252 while (count < end_mark) {
1253 edit_delete (edit, 1);
1254 count++;
1258 edit_set_markers (edit, 0, 0, 0, 0);
1259 edit->force |= REDRAW_PAGE;
1260 return 0;
1263 /* returns 1 if canceelled by user */
1264 int edit_block_delete_cmd (WEdit * edit)
1266 long start_mark, end_mark;
1267 if (eval_marks (edit, &start_mark, &end_mark)) {
1268 edit_delete_line (edit);
1269 return 0;
1271 return edit_block_delete (edit);
1274 #define INPUT_INDEX 9
1276 static gboolean
1277 editcmd_find (WEdit *edit, gsize *len)
1279 gsize search_start = edit->search_start;
1280 gsize search_end;
1282 if (edit->replace_backwards) {
1283 search_end = edit->curs1-1;
1284 while ((int) search_start >= 0) {
1285 if (search_end - search_start > edit->search->original_len && mc_search_is_fixed_search_str(edit->search))
1286 search_end = search_start + edit->search->original_len +1;
1287 if ( mc_search_run(edit->search, (void *) edit, search_start, search_end, len))
1289 return TRUE;
1291 search_start--;
1293 edit->search->error_str = g_strdup(_(" Search string not found "));
1294 } else {
1295 return mc_search_run(edit->search, (void *) edit, edit->search_start, edit->last_byte, len);
1297 return FALSE;
1301 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1302 (and the above) routines to work properly - paul */
1304 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1306 static char *
1307 edit_replace_cmd__conv_to_display(char *str)
1309 #ifdef HAVE_CHARSET
1310 GString *tmp;
1311 tmp = str_convert_to_display (str);
1313 if (tmp && tmp->len){
1314 g_free(str);
1315 str = tmp->str;
1317 g_string_free (tmp, FALSE);
1318 return str;
1319 #else
1320 return g_strdup(str);
1321 #endif
1324 static char *
1325 edit_replace_cmd__conv_to_input(char *str)
1327 #ifdef HAVE_CHARSET
1328 GString *tmp;
1329 tmp = str_convert_to_input (str);
1331 if (tmp && tmp->len){
1332 g_free(str);
1333 str = tmp->str;
1335 g_string_free (tmp, FALSE);
1336 return str;
1337 #else
1338 return g_strdup(str);
1339 #endif
1341 /* call with edit = 0 before shutdown to close memory leaks */
1342 void
1343 edit_replace_cmd (WEdit *edit, int again)
1345 /* 1 = search string, 2 = replace with */
1346 static char *saved1 = NULL; /* saved default[123] */
1347 static char *saved2 = NULL;
1348 char *input1 = NULL; /* user input from the dialog */
1349 char *input2 = NULL;
1350 char *str_for_prompt_dialog = NULL;
1351 int replace_yes;
1352 long times_replaced = 0, last_search;
1353 gboolean once_found = FALSE;
1355 if (!edit) {
1356 g_free (saved1), saved1 = NULL;
1357 g_free (saved2), saved2 = NULL;
1358 return;
1361 last_search = edit->last_byte;
1363 edit->force |= REDRAW_COMPLETELY;
1365 if (again && !saved1 && !saved2)
1366 again = 0;
1368 if (again) {
1369 input1 = g_strdup (saved1 ? saved1 : "");
1370 input2 = g_strdup (saved2 ? saved2 : "");
1371 } else {
1372 char *disp1 = edit_replace_cmd__conv_to_display(g_strdup (saved1 ? saved1 : ""));
1373 char *disp2 = edit_replace_cmd__conv_to_display(g_strdup (saved2 ? saved2 : ""));
1375 edit_push_action (edit, KEY_PRESS + edit->start_display);
1377 editcmd_dialog_replace_show (edit, disp1, disp2, &input1, &input2 );
1379 g_free (disp1);
1380 g_free (disp2);
1382 str_for_prompt_dialog = g_strdup(input2);
1384 if (input1 == NULL || *input1 == '\0') {
1385 edit->force = REDRAW_COMPLETELY;
1386 goto cleanup;
1389 input1 = edit_replace_cmd__conv_to_input(input1);
1390 input2 = edit_replace_cmd__conv_to_input(input2);
1392 g_free (saved1), saved1 = g_strdup (input1);
1393 g_free (saved2), saved2 = g_strdup (input2);
1395 if (edit->search)
1397 mc_search_free(edit->search);
1398 edit->search = NULL;
1402 if (!edit->search)
1404 edit->search = mc_search_new(input1, -1);
1405 if (edit->search == NULL)
1407 edit->search_start = edit->curs1;
1408 return;
1410 edit->search->search_type = edit->search_type;
1411 edit->search->is_all_charsets = edit->all_codepages;
1412 edit->search->is_case_sentitive = edit->replace_case;
1413 edit->search->search_fn = edit_search_cmd_callback;
1416 if (edit->found_len && edit->search_start == edit->found_start + 1
1417 && edit->replace_backwards)
1418 edit->search_start--;
1420 if (edit->found_len && edit->search_start == edit->found_start - 1
1421 && !edit->replace_backwards)
1422 edit->search_start++;
1424 do {
1425 gsize len = 0;
1426 long new_start;
1428 if (! editcmd_find(edit, &len))
1430 if (!(edit->search->error == MC_SEARCH_E_OK || (once_found && edit->search->error == MC_SEARCH_E_NOTFOUND)))
1432 edit_error_dialog (_ ("Search"), edit->search->error_str);
1434 break;
1436 once_found = TRUE;
1437 new_start = edit->search->normal_offset;
1439 edit->search_start = new_start = edit->search->normal_offset;
1440 /*returns negative on not found or error in pattern */
1442 if (edit->search_start >= 0) {
1443 int i;
1445 edit->found_start = edit->search_start;
1446 i = edit->found_len = len;
1448 edit_cursor_move (edit, edit->search_start - edit->curs1);
1449 edit_scroll_screen_over_cursor (edit);
1451 replace_yes = 1;
1453 if (edit->replace_mode==0) {
1454 int l;
1455 l = edit->curs_row - edit->num_widget_lines / 3;
1456 if (l > 0)
1457 edit_scroll_downward (edit, l);
1458 if (l < 0)
1459 edit_scroll_upward (edit, -l);
1461 edit_scroll_screen_over_cursor (edit);
1462 edit->force |= REDRAW_PAGE;
1463 edit_render_keypress (edit);
1465 /*so that undo stops at each query */
1466 edit_push_key_press (edit);
1468 switch (editcmd_dialog_replace_prompt_show (edit, str_for_prompt_dialog, /* and prompt 2/3 down */
1470 -1)) {
1471 case B_ENTER:
1472 break;
1473 case B_SKIP_REPLACE:
1474 replace_yes = 0;
1475 break;
1476 case B_REPLACE_ALL:
1477 edit->replace_mode=1;
1478 break;
1479 case B_REPLACE_ONE:
1480 break;
1481 case B_CANCEL:
1482 replace_yes = 0;
1483 break;
1486 if (replace_yes) { /* delete then insert new */
1487 GString *repl_str, *tmp_str;
1488 tmp_str = g_string_new(input2);
1490 repl_str = mc_search_prepare_replace_str (edit->search, tmp_str);
1491 g_string_free(tmp_str, TRUE);
1492 if (edit->search->error != MC_SEARCH_E_OK)
1494 edit_error_dialog (_ ("Replace"), edit->search->error_str);
1495 break;
1498 while (i--)
1499 edit_delete (edit, 1);
1501 while (++i < repl_str->len)
1502 edit_insert (edit, repl_str->str[i]);
1504 g_string_free(repl_str, TRUE);
1505 edit->found_len = i;
1507 /* so that we don't find the same string again */
1508 if (edit->replace_backwards) {
1509 last_search = edit->search_start;
1510 edit->search_start--;
1511 } else {
1512 edit->search_start += i;
1513 last_search = edit->last_byte;
1515 edit_scroll_screen_over_cursor (edit);
1516 } else {
1517 const char *msg = _(" Replace ");
1518 /* try and find from right here for next search */
1519 edit->search_start = edit->curs1;
1520 edit_update_curs_col (edit);
1522 edit->force |= REDRAW_PAGE;
1523 edit_render_keypress (edit);
1524 if (times_replaced) {
1525 message (D_NORMAL, msg, _(" %ld replacements made. "),
1526 times_replaced);
1527 } else
1528 query_dialog (msg, _(" Search string not found "),
1529 D_NORMAL, 1, _("&OK"));
1530 edit->replace_mode = -1;
1532 } while (edit->replace_mode >0);
1534 edit->force = REDRAW_COMPLETELY;
1535 edit_scroll_screen_over_cursor (edit);
1536 cleanup:
1537 g_free (str_for_prompt_dialog);
1538 g_free (input1);
1539 g_free (input2);
1543 void edit_search_cmd (WEdit * edit, int again)
1545 char *search_string = NULL, *search_string_dup = NULL;
1547 gsize len = 0;
1549 if (!edit)
1550 return;
1552 if (edit->search != NULL)
1553 search_string_dup = search_string = g_strndup(edit->search->original, edit->search->original_len);
1555 if (!again)
1557 #ifdef HAVE_CHARSET
1558 GString *tmp;
1559 if (search_string && *search_string)
1561 tmp = str_convert_to_display (search_string);
1563 g_free(search_string_dup);
1564 search_string_dup = NULL;
1566 if (tmp && tmp->len)
1567 search_string = search_string_dup = tmp->str;
1568 g_string_free (tmp, FALSE);
1570 #endif /* HAVE_CHARSET */
1571 editcmd_dialog_search_show (edit, &search_string);
1572 #ifdef HAVE_CHARSET
1573 if (search_string && *search_string)
1575 tmp = str_convert_to_input (search_string);
1576 if (tmp && tmp->len)
1577 search_string = tmp->str;
1579 g_string_free (tmp, FALSE);
1581 if (search_string_dup)
1582 g_free(search_string_dup);
1584 #endif /* HAVE_CHARSET */
1586 edit_push_action (edit, KEY_PRESS + edit->start_display);
1588 if (!search_string)
1590 edit->force |= REDRAW_COMPLETELY;
1591 edit_scroll_screen_over_cursor (edit);
1592 return;
1595 if (edit->search)
1597 mc_search_free(edit->search);
1598 edit->search = NULL;
1602 if (!edit->search)
1604 edit->search = mc_search_new(search_string, -1);
1605 if (edit->search == NULL)
1607 edit->search_start = edit->curs1;
1608 return;
1610 edit->search->search_type = edit->search_type;
1611 edit->search->is_all_charsets = edit->all_codepages;
1612 edit->search->is_case_sentitive = edit->replace_case;
1613 edit->search->search_fn = edit_search_cmd_callback;
1616 if (search_create_bookmark)
1618 edit_search_cmd_search_create_bookmark(edit);
1620 else
1622 if (edit->found_len && edit->search_start == edit->found_start + 1 && edit->replace_backwards)
1623 edit->search_start--;
1625 if (edit->found_len && edit->search_start == edit->found_start - 1 && !edit->replace_backwards)
1626 edit->search_start++;
1629 if (editcmd_find(edit, &len))
1631 edit->found_start = edit->search_start = edit->search->normal_offset;
1632 edit->found_len = len;
1634 edit_cursor_move (edit, edit->search_start - edit->curs1);
1635 edit_scroll_screen_over_cursor (edit);
1636 if (edit->replace_backwards)
1637 edit->search_start--;
1638 else
1639 edit->search_start++;
1641 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 /*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;