1 /* editor high level editing commands.
3 Copyright (C) 1996, 1997 the Free Software Foundation
5 Authors: 1996, 1997 Paul Sheer
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
32 #include "editcmddef.h"
35 #include "src/charsets.h"
40 /* search and replace: */
41 int replace_scanf
= 0;
42 int replace_regexp
= 0;
44 int replace_prompt
= 1;
45 int replace_whole
= 0;
47 int replace_backwards
= 0;
48 int search_create_bookmark
= 0;
50 /* queries on a save */
51 int edit_confirm_save
= 1;
53 #define NUM_REPL_ARGS 64
54 #define MAX_REPL_LEN 1024
56 static inline int my_lower_case (int c
)
58 return tolower(c
& 0xFF);
61 char *strcasechr (const unsigned char *s
, int c
)
63 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
71 static void *memmove (void *dest
, const void *src
, size_t n
)
81 t
= (char *) dest
+ n
;
88 #endif /* !HAVE_MEMMOVE */
90 /* #define itoa MY_itoa <---- this line is now in edit.h */
99 } while ((i
= i
/ 10));
105 /* Temporary strings */
106 static char *stacked
[16] =
107 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
110 This joins strings end on end and allocates memory for the result.
111 The result is later automatically free'd and must not be free'd
114 char *catstrs (const char *first
,...)
124 len
= strlen (first
);
125 va_start (ap
, first
);
127 while ((data
= va_arg (ap
, char *)) != 0)
128 len
+= strlen (data
);
135 stacked
[i
] = g_malloc (len
);
137 va_start (ap
, first
);
138 strcpy (stacked
[i
], first
);
139 while ((data
= va_arg (ap
, char *)) != 0)
140 strcat (stacked
[i
], data
);
146 /* Free temporary strings */
151 for (i
= 0; i
< sizeof(stacked
) / sizeof(stacked
[0]); i
++) {
157 void edit_help_cmd (WEdit
* edit
)
159 interactive_display (NULL
, "[Internal File Editor]");
160 edit
->force
|= REDRAW_COMPLETELY
;
163 void edit_refresh_cmd (WEdit
* edit
)
171 edit_get_syntax_color (edit
, -1, &color
);
174 #endif /* !HAVE_SLANG */
179 /* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
182 /* If 0 (quick save) then a) create/truncate <filename> file,
183 b) save to <filename>;
184 if 1 (safe save) then a) save to <tempnam>,
185 b) rename <tempnam> to <filename>;
186 if 2 (do backups) then a) save to <tempnam>,
187 b) rename <filename> to <filename.backup_ext>,
188 c) rename <tempnam> to <filename>. */
190 /* returns 0 on error */
191 int edit_save_file (WEdit
* edit
, const char *filename
)
196 int this_save_mode
, fd
;
203 if ((fd
= mc_open (filename
, O_WRONLY
)) == -1) {
205 * The file does not exists yet, so no safe save or
206 * backup are necessary.
211 this_save_mode
= option_save_mode
;
214 if (this_save_mode
> 0) {
215 char *savedir
, *slashpos
, *saveprefix
;
216 slashpos
= strrchr (filename
, PATH_SEP
);
218 savedir
= (char *) strdup (filename
);
219 savedir
[slashpos
- filename
+ 1] = '\0';
221 savedir
= (char *) strdup (".");
222 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
224 fd
= mc_mkstemps(&savename
, saveprefix
, NULL
);
229 * Close for now because mc_mkstemps use pure open system call
230 * to create temporary file and it needs to be reopened by
231 * VFS-aware mc_open() and MY_O_TEXT should be used.
235 savename
= g_strdup (filename
);
237 mc_chmod (savename
, edit
->stat1
.st_mode
);
238 mc_chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
240 if ((fd
= mc_open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| MY_O_TEXT
,
241 edit
->stat1
.st_mode
)) == -1)
245 if ((p
= (char *) edit_get_write_filter (savename
, filename
))) {
249 file
= (FILE *) popen (p
, "w");
252 filelen
= edit_write_stream (edit
, file
);
256 if (pclose (file
) != 0) {
257 edit_error_dialog (_ (" Error "), catstrs (_ (" Error writing to pipe: "), p
, " ", 0));
263 edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open pipe for writing: "), p
, " ", 0)));
268 #ifdef CR_LF_TRANSLATION
269 } else { /* optimised save */
270 filelen
= edit_write_stream (edit
, f
);
277 filelen
= edit
->last_byte
;
278 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
279 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
285 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], edit
->curs1
& M_EDIT_BUF_SIZE
) != (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
287 } else if (edit
->curs2
) {
289 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
290 if (mc_write (fd
, (char *) edit
->buffers2
[buf
] + EDIT_BUF_SIZE
- (edit
->curs2
& M_EDIT_BUF_SIZE
) - 1, 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) != 1 + (edit
->curs2
& M_EDIT_BUF_SIZE
)) {
294 if (mc_write (fd
, (char *) edit
->buffers2
[buf
], EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
304 #endif /* !CR_LF_TRANSLATION */
307 if (filelen
!= edit
->last_byte
)
309 if (this_save_mode
== 2)
310 if (mc_rename (filename
, catstrs (filename
, option_backup_ext
, 0)) == -1)
312 if (this_save_mode
> 0)
313 if (mc_rename (savename
, filename
) == -1)
325 I changed this from Oleg's original routine so
326 that option_backup_ext works with coolwidgets as well. This
327 does mean there is a memory leak - paul.
329 void menu_save_mode_cmd (void)
333 static char *str_result
;
334 static int save_mode_new
;
339 N_("Do backups -->")};
340 static QuickWidget widgets
[] =
342 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
343 B_CANCEL
, 0, 0, "c"},
344 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&Ok"), 0,
346 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
347 0, 0, &str_result
, "edit-backup-ext"},
348 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
349 0, 0, 0, "savemext"},
350 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
351 0, &save_mode_new
, str
, "t"},
353 static QuickDialog dialog
=
354 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
356 static int i18n_flag
= 0;
364 /* Ok/Cancel buttons */
365 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
366 maxlen
= max (maxlen
, l1
);
368 for (i
= 0; i
< 3; i
++ ) {
370 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
374 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
375 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
376 dlg_x
= min (COLS
, dlg_x
);
380 widgets
[1].relative_x
= i
;
381 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
383 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
385 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
386 widgets
[i
].x_divisions
= dlg_x
;
389 widgets
[2].text
= option_backup_ext
;
390 widgets
[4].value
= option_save_mode
;
391 if (quick_dialog (&dialog
) != B_ENTER
)
393 option_save_mode
= save_mode_new
;
394 option_backup_ext
= str_result
; /* this is a memory leak */
395 option_backup_ext_int
= 0;
396 str_result
[min (strlen (str_result
), sizeof (int))] = '\0';
397 memcpy ((char *) &option_backup_ext_int
, str_result
, strlen (option_backup_ext
));
400 void edit_split_filename (WEdit
* edit
, const char *f
)
403 free (edit
->filename
);
404 edit
->filename
= (char *) strdup (f
);
407 edit
->dir
= (char *) strdup ("");
410 /* Here we want to warn the users of overwriting an existing file,
411 but only if they have made a change to the filename */
412 /* returns 1 on success */
413 int edit_save_as_cmd (WEdit
* edit
)
415 /* This heads the 'Save As' dialog box */
417 int different_filename
= 0;
419 exp
= edit_get_save_file (edit
->dir
, edit
->filename
, _(" Save As "));
420 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
425 edit
->force
|= REDRAW_COMPLETELY
;
428 if (strcmp(catstrs (edit
->dir
, edit
->filename
, 0), exp
)) {
430 different_filename
= 1;
431 if ((file
= mc_open ((char *) exp
, O_RDONLY
)) != -1) { /* the file exists */
433 if (edit_query_dialog2 (_(" Warning "),
434 _(" A file already exists with this name. "),
435 /* Push buttons to over-write the current file, or cancel the operation */
436 _("Overwrite"), _("Cancel"))) {
437 edit
->force
|= REDRAW_COMPLETELY
;
443 if (edit_save_file (edit
, exp
)) {
444 edit_split_filename (edit
, exp
);
447 edit
->delete_file
= 0;
448 if (different_filename
&& !edit
->explicit_syntax
)
449 edit_load_syntax (edit
, 0, 0);
450 edit
->force
|= REDRAW_COMPLETELY
;
454 edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
455 edit
->force
|= REDRAW_COMPLETELY
;
460 edit
->force
|= REDRAW_COMPLETELY
;
464 /* {{{ Macro stuff starts here */
466 int raw_callback (struct Dlg_head
*h
, int key
, int Msg
)
470 common_dialog_repaint (h
);
481 /* gets a raw key from the keyboard. Passing cancel = 1 draws
482 a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
483 will return the next key pressed */
485 edit_raw_key_query (char *heading
, char *query
, int cancel
)
487 int w
= strlen (query
) + 7;
488 struct Dlg_head
*raw_dlg
= create_dlg (0, 0, 7, w
, dialog_colors
,
490 raw_callback
, "[Raw Key Query]",
492 DLG_CENTER
| DLG_TRYUP
|
494 x_set_dialog_title (raw_dlg
, heading
);
497 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
498 _("Cancel"), 0, 0, 0));
499 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
, 0));
501 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
503 w
= raw_dlg
->ret_value
;
504 destroy_dlg (raw_dlg
);
506 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
509 /* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
513 /* creates a macro file if it doesn't exist */
514 static FILE *edit_open_macro_file (const char *r
)
518 filename
= catstrs (home_dir
, MACRO_FILE
, 0);
519 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
522 return fopen (filename
, r
);
525 #define MAX_MACROS 1024
526 static int saved_macro
[MAX_MACROS
+ 1];
527 static int saved_macros_loaded
= 0;
530 This is just to stop the macro file be loaded over and over for keys
531 that aren't defined to anything. On slow systems this could be annoying.
533 int macro_exists (int k
)
536 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
537 if (saved_macro
[i
] == k
)
542 /* returns 1 on error */
543 int edit_delete_macro (WEdit
* edit
, int k
)
545 struct macro macro
[MAX_MACRO_LENGTH
];
549 if (saved_macros_loaded
)
550 if ((j
= macro_exists (k
)) < 0)
552 g
= fopen (catstrs (home_dir
, TEMP_FILE
, 0), "w");
554 /* This heads the delete macro error dialog box */
555 edit_error_dialog (_(" Delete macro "),
556 /* 'Open' = load temp file */
557 get_sys_error (_(" Error trying to open temp file ")));
560 f
= edit_open_macro_file ("r");
562 /* This heads the delete macro error dialog box */
563 edit_error_dialog (_(" Delete macro "),
564 /* 'Open' = load temp file */
565 get_sys_error (_(" Error trying to open macro file ")));
570 n
= fscanf (f
, ("key '%d 0': "), &s
);
574 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
578 fprintf (g
, ("key '%d 0': "), s
);
579 for (i
= 0; i
< n
; i
++)
580 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
586 if (rename (catstrs (home_dir
, TEMP_FILE
, 0), catstrs (home_dir
, MACRO_FILE
, 0)) == -1) {
587 /* This heads the delete macro error dialog box */
588 edit_error_dialog (_(" Delete macro "),
589 get_sys_error (_(" Error trying to overwrite macro file ")));
592 if (saved_macros_loaded
)
593 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
597 /* returns 0 on error */
598 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
603 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
604 /* This heads the 'Macro' dialog box */
605 s
= edit_raw_key_query (_(" Macro "),
606 /* Input line for a single key press follows the ':' */
607 _(" Press the macro's new hotkey: "), 1);
608 edit
->force
|= REDRAW_COMPLETELY
;
610 if (edit_delete_macro (edit
, s
))
612 f
= edit_open_macro_file ("a+");
614 fprintf (f
, ("key '%d 0': "), s
);
615 for (i
= 0; i
< n
; i
++)
616 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
619 if (saved_macros_loaded
) {
620 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
625 /* This heads the 'Save Macro' dialog box */
626 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
631 void edit_delete_macro_cmd (WEdit
* edit
)
635 command
= edit_raw_key_query (_ (" Delete Macro "),
636 _ (" Press macro hotkey: "), 1);
641 edit_delete_macro (edit
, command
);
644 /* return 0 on error */
645 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
648 int s
, i
= 0, found
= 0;
650 if (saved_macros_loaded
)
651 if (macro_exists (k
) < 0)
654 if ((f
= edit_open_macro_file ("r"))) {
658 u
= fscanf (f
, ("key '%d 0': "), &s
);
661 if (!saved_macros_loaded
)
662 saved_macro
[i
++] = s
;
665 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
668 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
673 } while (!found
|| !saved_macros_loaded
);
674 if (!saved_macros_loaded
) {
676 saved_macros_loaded
= 1;
681 /* This heads the 'Load Macro' dialog box */
682 edit_error_dialog (_(" Load macro "),
683 get_sys_error (_(" Error trying to open macro file ")));
687 /* }}} Macro stuff starts here */
689 /* returns 1 on success */
690 int edit_save_confirm_cmd (WEdit
* edit
)
694 if (edit_confirm_save
) {
695 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", 0);
696 /* Buttons to 'Confirm save file' query */
697 if (edit_query_dialog2 (_(" Save file "), f
, _("Save"), _("Cancel")))
700 return edit_save_cmd (edit
);
704 /* returns 1 on success */
705 int edit_save_cmd (WEdit
* edit
)
707 if (!edit_save_file (edit
, catstrs (edit
->dir
, edit
->filename
, 0)))
708 return edit_save_as_cmd (edit
);
709 edit
->force
|= REDRAW_COMPLETELY
;
711 edit
->delete_file
= 0;
717 /* returns 1 on success */
718 int edit_new_cmd (WEdit
* edit
)
720 if (edit
->modified
) {
721 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
722 edit
->force
|= REDRAW_COMPLETELY
;
726 edit
->force
|= REDRAW_COMPLETELY
;
728 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
731 /* returns 1 on error */
732 int edit_load_file_from_filename (WEdit
* edit
, char *exp
)
734 if (!edit_reload (edit
, exp
, 0, "", 0))
736 edit_split_filename (edit
, exp
);
741 int edit_load_cmd (WEdit
* edit
)
745 if (edit
->modified
) {
746 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
747 edit
->force
|= REDRAW_COMPLETELY
;
752 exp
= edit_get_load_file (edit
->dir
, edit
->filename
, _ (" Load "));
756 edit_load_file_from_filename (edit
, exp
);
759 edit
->force
|= REDRAW_COMPLETELY
;
764 if mark2 is -1 then marking is from mark1 to the cursor.
765 Otherwise its between the markers. This handles this.
766 Returns 1 if no text is marked.
768 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
770 if (edit
->mark1
!= edit
->mark2
) {
771 if (edit
->mark2
>= 0) {
772 *start_mark
= min (edit
->mark1
, edit
->mark2
);
773 *end_mark
= max (edit
->mark1
, edit
->mark2
);
775 *start_mark
= min (edit
->mark1
, edit
->curs1
);
776 *end_mark
= max (edit
->mark1
, edit
->curs1
);
777 edit
->column2
= edit
->curs_col
;
781 *start_mark
= *end_mark
= 0;
782 edit
->column2
= edit
->column1
= 0;
787 #define space_width 1
789 void edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
793 cursor
= edit
->curs1
;
794 col
= edit_get_col (edit
);
795 for (i
= 0; i
< size
; i
++) {
796 if (data
[i
] == '\n') { /* fill in and move to next line */
799 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
800 l
= width
- (edit_get_col (edit
) - col
);
802 edit_insert (edit
, ' ');
806 for (p
= edit
->curs1
;; p
++) {
807 if (p
== edit
->last_byte
)
808 edit_insert_ahead (edit
, '\n');
809 if (edit_get_byte (edit
, p
) == '\n') {
814 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
815 l
= col
- edit_get_col (edit
);
816 while (l
>= space_width
) {
817 edit_insert (edit
, ' ');
822 edit_insert (edit
, data
[i
]);
824 edit_cursor_move (edit
, cursor
- edit
->curs1
);
828 void edit_block_copy_cmd (WEdit
* edit
)
830 long start_mark
, end_mark
, current
= edit
->curs1
;
832 unsigned char *copy_buf
;
834 edit_update_curs_col (edit
);
836 if (eval_marks (edit
, &start_mark
, &end_mark
))
838 if (column_highlighting
)
839 if ((x
>= edit
->column1
&& x
< edit
->column2
) || (x
> edit
->column2
&& x
<= edit
->column1
))
842 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
844 /* all that gets pushed are deletes hence little space is used on the stack */
846 edit_push_markers (edit
);
848 if (column_highlighting
) {
849 edit_insert_column_of_text (edit
, copy_buf
, size
, abs (edit
->column2
- edit
->column1
));
852 edit_insert_ahead (edit
, copy_buf
[size
]);
856 edit_scroll_screen_over_cursor (edit
);
858 if (column_highlighting
) {
859 edit_set_markers (edit
, 0, 0, 0, 0);
860 edit_push_action (edit
, COLUMN_ON
);
861 column_highlighting
= 0;
862 } else if (start_mark
< current
&& end_mark
> current
)
863 edit_set_markers (edit
, start_mark
, end_mark
+ end_mark
- start_mark
, 0, 0);
865 edit
->force
|= REDRAW_PAGE
;
869 void edit_block_move_cmd (WEdit
* edit
)
873 unsigned char *copy_buf
;
874 long start_mark
, end_mark
;
878 if (eval_marks (edit
, &start_mark
, &end_mark
))
880 if (column_highlighting
) {
881 edit_update_curs_col (edit
);
883 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
884 if ((x
> edit
->column1
&& x
< edit
->column2
) || (x
> edit
->column2
&& x
< edit
->column1
))
886 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
889 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
890 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel")))
893 edit_push_markers (edit
);
894 current
= edit
->curs1
;
895 if (column_highlighting
) {
896 int size
, c1
, c2
, line
;
897 line
= edit
->curs_line
;
899 edit_mark_cmd (edit
, 0);
900 c1
= min (edit
->column1
, edit
->column2
);
901 c2
= max (edit
->column1
, edit
->column2
);
902 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
904 edit_block_delete_cmd (edit
);
907 edit_move_to_line (edit
, line
);
908 edit_cursor_move (edit
, edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), x
, 0) - edit
->curs1
);
909 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
911 line
= edit
->curs_line
;
912 edit_update_curs_col (edit
);
914 edit_block_delete_cmd (edit
);
915 edit_move_to_line (edit
, line
);
916 edit_cursor_move (edit
, edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), x
, 0) - edit
->curs1
);
918 edit_set_markers (edit
, 0, 0, 0, 0);
919 edit_push_action (edit
, COLUMN_ON
);
920 column_highlighting
= 0;
922 copy_buf
= malloc (end_mark
- start_mark
);
923 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
924 edit_scroll_screen_over_cursor (edit
);
926 while (count
< end_mark
) {
927 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
930 edit_scroll_screen_over_cursor (edit
);
931 edit_cursor_move (edit
, current
- edit
->curs1
- (((current
- edit
->curs1
) > 0) ? end_mark
- start_mark
: 0));
932 edit_scroll_screen_over_cursor (edit
);
933 while (count
-- > start_mark
)
934 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
935 edit_set_markers (edit
, edit
->curs1
, edit
->curs1
+ end_mark
- start_mark
, 0, 0);
937 edit_scroll_screen_over_cursor (edit
);
939 edit
->force
|= REDRAW_PAGE
;
942 void edit_cursor_to_bol (WEdit
* edit
);
944 void edit_delete_column_of_text (WEdit
* edit
)
946 long p
, q
, r
, m1
, m2
;
950 eval_marks (edit
, &m1
, &m2
);
951 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
952 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
953 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
959 r
= edit_bol (edit
, edit
->curs1
);
960 p
= edit_move_forward3 (edit
, r
, b
, 0);
961 q
= edit_move_forward3 (edit
, r
, c
, 0);
966 edit_cursor_move (edit
, p
- edit
->curs1
);
967 while (q
> p
) { /* delete line between margins */
968 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
972 if (n
) /* move to next line except on the last delete */
973 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
977 /* if success return 0 */
978 int edit_block_delete (WEdit
* edit
)
981 long start_mark
, end_mark
;
982 if (eval_marks (edit
, &start_mark
, &end_mark
))
984 if (column_highlighting
&& edit
->mark2
< 0)
985 edit_mark_cmd (edit
, 0);
986 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
987 /* Warning message with a query to continue or cancel the operation */
988 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel ")))
990 edit_push_markers (edit
);
991 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
992 edit_scroll_screen_over_cursor (edit
);
994 if (start_mark
< end_mark
) {
995 if (column_highlighting
) {
997 edit_mark_cmd (edit
, 0);
998 edit_delete_column_of_text (edit
);
1000 while (count
< end_mark
) {
1006 edit_set_markers (edit
, 0, 0, 0, 0);
1007 edit
->force
|= REDRAW_PAGE
;
1011 /* returns 1 if canceelled by user */
1012 int edit_block_delete_cmd (WEdit
* edit
)
1014 long start_mark
, end_mark
;
1015 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1016 edit_delete_line (edit
);
1019 return edit_block_delete (edit
);
1023 #define INPUT_INDEX 9
1024 #define SEARCH_DLG_WIDTH 58
1025 #define SEARCH_DLG_HEIGHT 10
1026 #define REPLACE_DLG_WIDTH 58
1027 #define REPLACE_DLG_HEIGHT 15
1028 #define CONFIRM_DLG_WIDTH 79
1029 #define CONFIRM_DLG_HEIGTH 6
1030 #define B_REPLACE_ALL B_USER+1
1031 #define B_REPLACE_ONE B_USER+2
1032 #define B_SKIP_REPLACE B_USER+3
1034 int edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1036 QuickWidget quick_widgets
[] =
1038 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1039 0, B_CANCEL
, 0, 0, NULL
},
1040 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("o&Ne"),
1041 0, B_REPLACE_ONE
, 0, 0, NULL
},
1042 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("al&L"),
1043 0, B_REPLACE_ALL
, 0, 0, NULL
},
1044 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1045 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1046 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1047 0, B_ENTER
, 0, 0, NULL
},
1048 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1053 char *msg
= _(" Replace with: ");
1055 quick_widgets
[5].text
= catstrs (msg
, replace_text
, 0);
1058 convert_to_display (quick_widgets
[5].text
+ strlen (msg
));
1060 quick_widgets
[5].text
= catstrs (_ (" Replace with: "), replace_text
, 0);
1061 #endif /* !HAVE_CHARSET */
1064 QuickDialog Quick_input
=
1065 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1066 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1068 Quick_input
.widgets
= quick_widgets
;
1070 Quick_input
.xpos
= xpos
;
1072 /* Sometimes menu can hide replaced text. I don't like it */
1074 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1075 ypos
-= CONFIRM_DLG_HEIGTH
;
1077 Quick_input
.ypos
= ypos
;
1078 return quick_dialog (&Quick_input
);
1082 void edit_replace_dialog (WEdit
* edit
, char **search_text
, char **replace_text
, char **arg_order
)
1084 int treplace_scanf
= replace_scanf
;
1085 int treplace_regexp
= replace_regexp
;
1086 int treplace_all
= replace_all
;
1087 int treplace_prompt
= replace_prompt
;
1088 int treplace_backwards
= replace_backwards
;
1089 int treplace_whole
= replace_whole
;
1090 int treplace_case
= replace_case
;
1092 QuickWidget quick_widgets
[] =
1094 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1096 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
1098 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1100 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1102 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pr&Ompt on replace"), 0, 0,
1104 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1106 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1108 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1110 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1112 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1114 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1116 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1118 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1120 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1122 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1126 quick_widgets
[2].result
= &treplace_scanf
;
1127 quick_widgets
[3].result
= &treplace_all
;
1128 quick_widgets
[4].result
= &treplace_prompt
;
1129 quick_widgets
[5].result
= &treplace_backwards
;
1130 quick_widgets
[6].result
= &treplace_regexp
;
1131 quick_widgets
[7].result
= &treplace_whole
;
1132 quick_widgets
[8].result
= &treplace_case
;
1133 quick_widgets
[9].str_result
= arg_order
;
1134 quick_widgets
[9].text
= *arg_order
;
1135 quick_widgets
[11].str_result
= replace_text
;
1136 quick_widgets
[11].text
= *replace_text
;
1137 quick_widgets
[13].str_result
= search_text
;
1138 quick_widgets
[13].text
= *search_text
;
1140 QuickDialog Quick_input
=
1141 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1142 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1144 Quick_input
.widgets
= quick_widgets
;
1146 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1147 replace_scanf
= treplace_scanf
;
1148 replace_backwards
= treplace_backwards
;
1149 replace_regexp
= treplace_regexp
;
1150 replace_all
= treplace_all
;
1151 replace_prompt
= treplace_prompt
;
1152 replace_whole
= treplace_whole
;
1153 replace_case
= treplace_case
;
1157 *replace_text
= NULL
;
1158 *search_text
= NULL
;
1165 void edit_search_dialog (WEdit
* edit
, char **search_text
)
1167 int treplace_scanf
= replace_scanf
;
1168 int treplace_regexp
= replace_regexp
;
1169 int treplace_whole
= replace_whole
;
1170 int treplace_case
= replace_case
;
1171 int treplace_backwards
= replace_backwards
;
1173 QuickWidget quick_widgets
[] =
1175 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1177 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
1179 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1181 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1183 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1185 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1187 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1189 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1191 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1195 quick_widgets
[2].result
= &treplace_scanf
;
1196 quick_widgets
[3].result
= &treplace_backwards
;
1197 quick_widgets
[4].result
= &treplace_regexp
;
1198 quick_widgets
[5].result
= &treplace_whole
;
1199 quick_widgets
[6].result
= &treplace_case
;
1200 quick_widgets
[7].str_result
= search_text
;
1201 quick_widgets
[7].text
= *search_text
;
1204 QuickDialog Quick_input
=
1205 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_(" Search "),
1206 "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
1208 Quick_input
.widgets
= quick_widgets
;
1210 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1211 replace_scanf
= treplace_scanf
;
1212 replace_backwards
= treplace_backwards
;
1213 replace_regexp
= treplace_regexp
;
1214 replace_whole
= treplace_whole
;
1215 replace_case
= treplace_case
;
1217 *search_text
= NULL
;
1223 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1225 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1226 sargs[4], sargs[5], sargs[6], sargs[7], \
1227 sargs[8], sargs[9], sargs[10], sargs[11], \
1228 sargs[12], sargs[13], sargs[14], sargs[15]
1230 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1231 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1232 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1233 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1236 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1237 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1238 int string_regexp_search (char *pattern
, char *string
, int len
, int match_type
, int match_bol
, int icase
, int *found_len
, void *d
)
1241 static char *old_pattern
= NULL
;
1242 static int old_type
, old_icase
;
1244 static regmatch_t s
[1];
1246 pmatch
= (regmatch_t
*) d
;
1250 if (!old_pattern
|| strcmp (old_pattern
, pattern
) || old_type
!= match_type
|| old_icase
!= icase
) {
1256 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0))) {
1260 old_pattern
= (char *) strdup (pattern
);
1261 old_type
= match_type
;
1264 if (regexec (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
, ((match_bol
|| match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1268 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1269 return (pmatch
[0].rm_so
);
1272 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1273 (and the above) routines to work properly - paul */
1275 long edit_find_string (long start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, int once_only
, void *d
)
1278 long l
= strlen ((char *) exp
), f
= 0;
1281 for (p
= 0; p
< l
; p
++) /* count conversions... */
1283 if (exp
[++p
] != '%') /* ...except for "%%" */
1286 if (replace_scanf
|| replace_regexp
) {
1289 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1291 replace_scanf
= (!replace_regexp
); /* can't have both */
1295 if (replace_scanf
) {
1296 unsigned char e
[MAX_REPL_LEN
];
1297 if (n
>= NUM_REPL_ARGS
)
1301 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1302 buf
[p
- start
] = (*get_byte
) (data
, p
);
1304 for (p
= 0; exp
[p
] != 0; p
++)
1305 exp
[p
] = my_lower_case (exp
[p
]);
1306 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1307 c
= (*get_byte
) (data
, p
);
1308 buf
[p
- start
] = my_lower_case (c
);
1312 buf
[(q
= p
- start
)] = 0;
1313 strcpy ((char *) e
, (char *) exp
);
1314 strcat ((char *) e
, "%n");
1318 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1319 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1320 if (*((int *) sargs
[n
])) {
1321 *len
= *((int *) sargs
[n
]);
1327 if (q
+ start
< last_byte
) {
1329 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1331 c
= (*get_byte
) (data
, q
+ start
);
1332 buf
[q
] = my_lower_case (c
);
1338 buf
++; /* move the window along */
1339 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1340 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1345 } else { /* regexp matching */
1347 int found_start
, match_bol
, move_win
= 0;
1349 while (start
+ offset
< last_byte
) {
1350 match_bol
= (offset
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1355 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1356 mbuf
[q
] = (*get_byte
) (data
, p
);
1357 if (mbuf
[q
] == '\n')
1366 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, q
, match_normal
, match_bol
, !replace_case
, len
, d
);
1368 if (found_start
<= -2) { /* regcomp/regexec error */
1372 else if (found_start
== -1) /* not found: try next line */
1374 else if (*len
== 0) { /* null pattern: try again at next character */
1381 return (start
+ offset
- q
+ found_start
);
1386 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1387 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1388 q
= strlen ((char *) buf
);
1389 memmove (mbuf
, buf
, q
);
1398 *len
= strlen ((char *) exp
);
1400 for (p
= start
; p
<= last_byte
- l
; p
++) {
1401 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1402 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1403 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1412 for (p
= 0; exp
[p
] != 0; p
++)
1413 exp
[p
] = my_lower_case (exp
[p
]);
1415 for (p
= start
; p
<= last_byte
- l
; p
++) {
1416 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1417 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1418 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1432 long edit_find_forwards (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, int once_only
, void *d
)
1433 { /*front end to find_string to check for
1438 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1439 if (replace_whole
) {
1440 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1441 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1442 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1450 p
++; /*not a whole word so continue search. */
1455 long edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, void *d
)
1458 if (replace_backwards
) {
1459 while (search_start
>= 0) {
1460 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1461 if (p
== search_start
)
1466 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1471 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1473 #define snprintf(v) { \
1478 sprintf(s,q1,v,&n); \
1482 /* this function uses the sprintf command to do a vprintf */
1483 /* it takes pointers to arguments instead of the arguments themselves */
1484 static int sprintf_p (char *str
, const char *fmt
,...)
1485 __attribute__ ((format (printf
, 2, 3)));
1487 static int sprintf_p (char *str
, const char *fmt
,...)
1491 char *q
, *p
, *s
= str
;
1496 p
= q
= (char *) fmt
;
1498 while ((p
= strchr (p
, '%'))) {
1500 strncpy (s
, q
, n
); /* copy stuff between format specifiers */
1528 strcpy (p1
, itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1531 while (is_digit (*p
))
1538 strcpy (p1
, itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1541 while (is_digit (*p
))
1544 /* flags done, now get argument */
1546 snprintf (va_arg (ap
, char *));
1547 } else if (*p
== 'h') {
1548 if (strchr ("diouxX", *p
))
1549 snprintf (*va_arg (ap
, short *));
1550 } else if (*p
== 'l') {
1552 if (strchr ("diouxX", *p
))
1553 snprintf (*va_arg (ap
, long *));
1554 } else if (strchr ("cdiouxX", *p
)) {
1555 snprintf (*va_arg (ap
, int *));
1556 } else if (*p
== 'L') {
1558 if (strchr ("EefgG", *p
))
1559 snprintf (*va_arg (ap
, double *)); /* should be long double */
1560 } else if (strchr ("EefgG", *p
)) {
1561 snprintf (*va_arg (ap
, double *));
1562 } else if (strchr ("DOU", *p
)) {
1563 snprintf (*va_arg (ap
, long *));
1564 } else if (*p
== 'p') {
1565 snprintf (*va_arg (ap
, void **));
1570 sprintf (s
, q
); /* print trailing leftover */
1571 return s
- str
+ strlen (s
);
1574 static void regexp_error (WEdit
*edit
)
1576 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1577 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
1580 /* call with edit = 0 before shutdown to close memory leaks */
1581 void edit_replace_cmd (WEdit
* edit
, int again
)
1583 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1584 static char *old1
= NULL
;
1585 static char *old2
= NULL
;
1586 static char *old3
= NULL
;
1591 int replace_continue
;
1592 int treplace_prompt
= 0;
1594 long times_replaced
= 0, last_search
;
1595 int argord
[NUM_REPL_ARGS
];
1612 last_search
= edit
->last_byte
;
1614 edit
->force
|= REDRAW_COMPLETELY
;
1616 exp1
= old1
? old1
: exp1
;
1617 exp2
= old2
? old2
: exp2
;
1618 exp3
= old3
? old3
: exp3
;
1623 exp1
= g_strdup (old1
);
1624 exp2
= g_strdup (old2
);
1625 exp3
= g_strdup (old3
);
1627 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1631 convert_to_display (exp1
);
1633 convert_to_display (exp2
);
1634 #endif /* HAVE_CHARSET */
1636 edit_replace_dialog (edit
, &exp1
, &exp2
, &exp3
);
1640 convert_from_input (exp1
);
1642 convert_from_input (exp2
);
1643 #endif /* HAVE_CHARSET */
1645 treplace_prompt
= replace_prompt
;
1648 if (!exp1
|| !*exp1
) {
1649 edit
->force
= REDRAW_COMPLETELY
;
1664 old1
= g_strdup (exp1
);
1665 old2
= g_strdup (exp2
);
1666 old3
= g_strdup (exp3
);
1671 while ((s
= strchr (exp3
, ' ')))
1672 memmove (s
, s
+ 1, strlen (s
));
1674 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1675 if (s
!= (char *)1 && *s
) {
1677 if ((ord
> 0) && (ord
< NUM_REPL_ARGS
))
1678 argord
[i
] = ord
- 1;
1681 s
= strchr (s
, ',') + 1;
1687 replace_continue
= replace_all
;
1689 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1690 edit
->search_start
--;
1692 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1693 edit
->search_start
++;
1698 new_start
= edit_find (edit
->search_start
, (unsigned char *) exp1
, &len
, last_search
,
1699 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, pmatch
);
1700 if (new_start
== -3) {
1701 regexp_error (edit
);
1704 edit
->search_start
= new_start
;
1705 /*returns negative on not found or error in pattern */
1707 if (edit
->search_start
>= 0) {
1708 edit
->found_start
= edit
->search_start
;
1709 i
= edit
->found_len
= len
;
1711 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1712 edit_scroll_screen_over_cursor (edit
);
1716 if (treplace_prompt
) {
1718 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1720 edit_scroll_downward (edit
, l
);
1722 edit_scroll_upward (edit
, -l
);
1724 edit_scroll_screen_over_cursor (edit
);
1725 edit
->force
|= REDRAW_PAGE
;
1726 edit_render_keypress (edit
);
1728 /*so that undo stops at each query */
1729 edit_push_key_press (edit
);
1731 switch (edit_replace_prompt (edit
, exp2
, /* and prompt 2/3 down */
1732 (edit
->num_widget_columns
- CONFIRM_DLG_WIDTH
)/2,
1733 edit
->num_widget_lines
* 2 / 3)) {
1736 case B_SKIP_REPLACE
:
1740 treplace_prompt
= 0;
1741 replace_continue
= 1;
1744 replace_continue
= 0;
1748 replace_continue
= 0;
1752 if (replace_yes
) { /* delete then insert new */
1753 if (replace_scanf
|| replace_regexp
) {
1754 char repl_str
[MAX_REPL_LEN
+ 2];
1755 if (replace_regexp
) { /* we need to fill in sargs just like with scanf */
1757 for (k
= 1; k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0; k
++) {
1759 t
= (unsigned char *) &sargs
[k
- 1][0];
1760 for (j
= 0; j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
&& j
< 255; j
++, t
++)
1761 *t
= (unsigned char) edit_get_byte (edit
, edit
->search_start
- pmatch
[0].rm_so
+ pmatch
[k
].rm_so
+ j
);
1764 for (; k
<= NUM_REPL_ARGS
; k
++)
1765 sargs
[k
- 1][0] = 0;
1767 if (sprintf_p (repl_str
, exp2
, PRINTF_ARGS
) >= 0) {
1771 while (repl_str
[++i
])
1772 edit_insert (edit
, repl_str
[i
]);
1774 edit_error_dialog (_ (" Replace "),
1775 /* "Invalid regexp string or scanf string" */
1776 _ (" Error in replacement format string. "));
1777 replace_continue
= 0;
1784 edit_insert (edit
, exp2
[i
]);
1786 edit
->found_len
= i
;
1788 /* so that we don't find the same string again */
1789 if (replace_backwards
) {
1790 last_search
= edit
->search_start
;
1791 edit
->search_start
--;
1793 edit
->search_start
+= i
;
1794 last_search
= edit
->last_byte
;
1796 edit_scroll_screen_over_cursor (edit
);
1798 edit
->search_start
= edit
->curs1
; /* try and find from right here for next search */
1799 edit_update_curs_col (edit
);
1801 edit
->force
|= REDRAW_PAGE
;
1802 edit_render_keypress (edit
);
1803 if (times_replaced
) {
1804 message (0, _(" Replace "), _(" %ld replacements made. "), times_replaced
);
1806 edit_message_dialog (_ (" Replace "), _ (" Search string not found. "));
1807 replace_continue
= 0;
1809 } while (replace_continue
);
1814 edit
->force
= REDRAW_COMPLETELY
;
1815 edit_scroll_screen_over_cursor (edit
);
1821 void edit_search_cmd (WEdit
* edit
, int again
)
1823 static char *old
= NULL
;
1833 exp
= old
? old
: exp
;
1834 if (again
) { /*ctrl-hotkey for search again. */
1837 exp
= (char *) g_strdup (old
);
1842 convert_to_display (exp
);
1843 #endif /* HAVE_CHARSET */
1845 edit_search_dialog (edit
, &exp
);
1849 convert_from_input (exp
);
1850 #endif /* HAVE_CHARSET */
1852 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1860 old
= (char *) g_strdup (exp
);
1862 if (search_create_bookmark
) {
1863 int found
= 0, books
= 0;
1864 int l
= 0, l_last
= -1;
1867 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1868 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1872 l
+= edit_count_lines (edit
, q
, p
);
1874 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
1881 /* in response to number of bookmarks added because of string being found %d times */
1882 message (0, _(" Search "), _(" %d finds made, %d bookmarks added "), found
, books
);
1884 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1888 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1889 edit
->search_start
--;
1891 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1892 edit
->search_start
++;
1894 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1895 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1897 if (edit
->search_start
>= 0) {
1898 edit
->found_start
= edit
->search_start
;
1899 edit
->found_len
= len
;
1901 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1902 edit_scroll_screen_over_cursor (edit
);
1903 if (replace_backwards
)
1904 edit
->search_start
--;
1906 edit
->search_start
++;
1907 } else if (edit
->search_start
== -3) {
1908 edit
->search_start
= edit
->curs1
;
1909 regexp_error (edit
);
1911 edit
->search_start
= edit
->curs1
;
1912 edit_error_dialog (_ (" Search "), _ (" Search string not found. "));
1918 edit
->force
|= REDRAW_COMPLETELY
;
1919 edit_scroll_screen_over_cursor (edit
);
1923 /* Real edit only */
1924 void edit_quit_cmd (WEdit
* edit
)
1926 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1928 edit
->force
|= REDRAW_COMPLETELY
;
1929 if (edit
->modified
) {
1930 switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
1932 edit_push_markers (edit
);
1933 edit_set_markers (edit
, 0, 0, 0, 0);
1934 if (!edit_save_cmd (edit
))
1938 if (edit
->delete_file
)
1939 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1946 else if (edit
->delete_file
)
1947 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1948 dlg_stop (edit
->widget
.parent
);
1951 #define TEMP_BUF_LEN 1024
1953 /* returns a null terminated length of text. Result must be free'd */
1954 unsigned char *edit_get_block (WEdit
* edit
, long start
, long finish
, int *l
)
1956 unsigned char *s
, *r
;
1957 r
= s
= malloc (finish
- start
+ 1);
1958 if (column_highlighting
) {
1960 while (start
< finish
) { /* copy from buffer, excluding chars that are out of the column 'margins' */
1962 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0, start
);
1963 c
= edit_get_byte (edit
, start
);
1964 if ((x
>= edit
->column1
&& x
< edit
->column2
)
1965 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
1972 *l
= finish
- start
;
1973 while (start
< finish
)
1974 *s
++ = edit_get_byte (edit
, start
++);
1980 /* save block, returns 1 on success */
1981 int edit_save_block (WEdit
* edit
, const char *filename
, long start
, long finish
)
1985 if ((file
= mc_open ((char *) filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
1988 if (column_highlighting
) {
1989 unsigned char *block
, *p
;
1991 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
1993 r
= mc_write (file
, p
, len
);
2003 len
= finish
- start
;
2004 buf
= malloc (TEMP_BUF_LEN
);
2005 while (start
!= finish
) {
2006 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2007 for (; i
< end
; i
++)
2008 buf
[i
- start
] = edit_get_byte (edit
, i
);
2009 len
-= mc_write (file
, (char *) buf
, end
- start
);
2020 /* copies a block to clipboard file */
2021 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2023 return edit_save_block (edit
, catstrs (home_dir
, CLIP_FILE
, 0), start
, finish
);
2027 void edit_paste_from_history (WEdit
*edit
)
2031 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2033 long start_mark
, end_mark
;
2034 if (eval_marks (edit
, &start_mark
, &end_mark
))
2036 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2037 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2040 edit_mark_cmd (edit
, 1);
2044 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2046 long start_mark
, end_mark
;
2047 if (eval_marks (edit
, &start_mark
, &end_mark
))
2049 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2050 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2053 edit_block_delete_cmd (edit
);
2054 edit_mark_cmd (edit
, 1);
2058 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2060 edit_insert_file (edit
, catstrs (home_dir
, CLIP_FILE
, 0));
2064 void edit_goto_cmd (WEdit
*edit
)
2069 sprintf (s
, "%d", l
);
2070 f
= input_dialog (_(" Goto line "), _(" Enter line: "), l
? s
: "");
2074 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2075 edit_move_to_line (edit
, l
- 1);
2076 edit
->force
|= REDRAW_COMPLETELY
;
2082 /*returns 1 on success */
2083 int edit_save_block_cmd (WEdit
* edit
)
2085 long start_mark
, end_mark
;
2087 if (eval_marks (edit
, &start_mark
, &end_mark
))
2089 exp
= edit_get_save_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Save Block "));
2090 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2096 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2098 edit
->force
|= REDRAW_COMPLETELY
;
2102 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2106 edit
->force
|= REDRAW_COMPLETELY
;
2111 /* returns 1 on success */
2112 int edit_insert_file_cmd (WEdit
* edit
)
2114 char *exp
= edit_get_load_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Insert File "));
2115 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2121 if (edit_insert_file (edit
, exp
)) {
2123 edit
->force
|= REDRAW_COMPLETELY
;
2127 edit_error_dialog (_ (" Insert file "), get_sys_error (_ (" Error trying to insert file. ")));
2131 edit
->force
|= REDRAW_COMPLETELY
;
2135 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2136 int edit_sort_cmd (WEdit
* edit
)
2138 static char *old
= 0;
2140 long start_mark
, end_mark
;
2143 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2144 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2147 edit_save_block (edit
, catstrs (home_dir
, BLOCK_FILE
, 0), start_mark
, end_mark
);
2149 exp
= old
? old
: "";
2151 exp
= input_dialog (_(" Run Sort "),
2152 _(" Enter sort options (see manpage) separated by whitespace: "), exp
);
2160 e
= system (catstrs (" sort ", exp
, " ", home_dir
, BLOCK_FILE
, " > ", home_dir
, TEMP_FILE
, 0));
2162 if (e
== -1 || e
== 127) {
2163 edit_error_dialog (_(" Sort "),
2164 get_sys_error (_(" Error trying to execute sort command ")));
2167 sprintf (q
, "%d ", e
);
2168 edit_error_dialog (_(" Sort "),
2169 catstrs (_(" Sort returned non-zero: "), q
, 0));
2174 edit
->force
|= REDRAW_COMPLETELY
;
2176 if (edit_block_delete_cmd (edit
))
2178 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, 0));
2182 /* if block is 1, a block must be highlighted and the shell command
2183 processes it. If block is 0 the shell command is a straight system
2184 command, that just produces some output which is to be inserted */
2186 edit_block_process_cmd (WEdit
* edit
, const char *shell_cmd
, int block
)
2188 long start_mark
, end_mark
;
2191 FILE *script_home
= NULL
;
2192 FILE *script_src
= NULL
;
2193 FILE *block_file
= NULL
;
2199 o
= g_strconcat (mc_home
, shell_cmd
, 0); /* original source script */
2200 h
= g_strconcat (home_dir
, EDIT_DIR
, shell_cmd
, 0); /* home script */
2201 b
= g_strconcat (home_dir
, BLOCK_FILE
, 0); /* block file */
2202 e
= g_strconcat (home_dir
, ERROR_FILE
, 0); /* error file */
2204 if (!(script_home
= fopen (h
, "r"))) {
2205 if (!(script_home
= fopen (h
, "w"))) {
2206 edit_error_dialog ("", get_sys_error (g_strconcat
2208 ("Error create script:"),
2212 if (!(script_src
= fopen (o
, "r"))) {
2213 fclose (script_home
);
2215 edit_error_dialog ("", get_sys_error (g_strconcat
2216 (_("Error read script:"),
2220 while (fgets (buf
, sizeof (buf
), script_src
))
2221 fputs (buf
, script_home
);
2222 if (fclose (script_home
)) {
2223 edit_error_dialog ("", get_sys_error (g_strconcat
2225 ("Error close script:"),
2230 edit_error_dialog ("", get_sys_error (g_strconcat
2231 (_("Script created:"), h
,
2234 if (block
) { /* for marked block run indent formatter */
2235 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2236 edit_error_dialog (_("Process block"),
2238 (" You must first highlight a block of text. "));
2241 edit_save_block (edit
, b
, start_mark
, end_mark
);
2245 * Initial space is to avoid polluting bash history.
2247 * $1 - name of the edited file (to check its extention etc).
2248 * $2 - file containing the current block.
2249 * $3 - file where error messages should be put.
2251 execute (g_strconcat (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2252 edit
->filename
, " ", home_dir
, BLOCK_FILE
,
2253 " ", home_dir
, ERROR_FILE
, NULL
));
2257 * No block selected, just execute the command for the file.
2259 * $1 - name of the edited file.
2261 execute (g_strconcat (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2262 edit
->filename
, NULL
));
2265 edit_refresh_cmd (edit
);
2266 edit
->force
|= REDRAW_COMPLETELY
;
2268 /* insert result block */
2270 if (mc_stat (e
, &s
) == 0) {
2271 if (!s
.st_size
) { /* no error messages */
2272 if (edit_block_delete_cmd (edit
))
2274 edit_insert_file (edit
, b
);
2276 edit_insert_file (edit
, e
);
2279 edit_error_dialog ("",
2280 get_sys_error (g_strconcat
2282 ("Error trying to stat file:"),
2284 edit
->force
|= REDRAW_COMPLETELY
;
2286 if ((block_file
= fopen (b
, "w")))
2287 fclose (block_file
);
2300 /* prints at the cursor */
2301 /* returns the number of chars printed */
2302 int edit_print_string (WEdit
* e
, const char *s
)
2306 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2307 e
->force
|= REDRAW_COMPLETELY
;
2308 edit_update_screen (e
);
2312 int edit_printf (WEdit
* e
, const char *fmt
,...)
2318 sprintf (s
, fmt
, pa
);
2319 i
= edit_print_string (e
, s
);
2324 /* FIXME: does this function break NT_OS2 ? */
2326 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2331 s
= g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject
, cc
, to
);
2340 for (i
= 0; i
< edit
->last_byte
; i
++)
2341 fputc (edit_get_byte (edit
, i
), p
);
2346 #define MAIL_DLG_HEIGHT 12
2348 void edit_mail_dialog (WEdit
* edit
)
2351 char *tmail_subject
;
2354 static char *mail_cc_last
= 0;
2355 static char *mail_subject_last
= 0;
2356 static char *mail_to_last
= 0;
2358 QuickDialog Quick_input
=
2359 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2360 "[Input Line Keys]", "quick_input", 0};
2362 QuickWidget quick_widgets
[] =
2364 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2366 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
2368 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2369 0, "mail-dlg-input"},
2370 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2372 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2373 0, "mail-dlg-input-2"},
2374 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2376 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2377 0, "mail-dlg-input-3"},
2378 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2380 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2384 quick_widgets
[2].str_result
= &tmail_cc
;
2385 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2386 quick_widgets
[4].str_result
= &tmail_subject
;
2387 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2388 quick_widgets
[6].str_result
= &tmail_to
;
2389 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2391 Quick_input
.widgets
= quick_widgets
;
2393 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2395 g_free (mail_cc_last
);
2396 if (mail_subject_last
)
2397 g_free (mail_subject_last
);
2399 g_free (mail_to_last
);
2400 mail_cc_last
= *(quick_widgets
[2].str_result
);
2401 mail_subject_last
= *(quick_widgets
[4].str_result
);
2402 mail_to_last
= *(quick_widgets
[6].str_result
);
2403 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2408 /*******************/
2409 /* Word Completion */
2410 /*******************/
2413 /* find first character of current word */
2414 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2418 /* return if at begin of file */
2419 if (edit
->curs1
<= 0)
2422 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2423 /* return if not at end or in word */
2424 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2427 /* search start of word to be completed */
2429 /* return if at begin of file */
2430 if (edit
->curs1
- i
< 0)
2434 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2436 if (!(isalnum (c
) || c
== '_')) {
2437 /* return if word starts with digit */
2441 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2451 /* (re)set search parameters to the given values */
2452 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2455 replace_backwards
= rb
;
2456 replace_regexp
= rr
;
2462 const static int MAX_WORD_COMPLETIONS
= 100; /* in listbox */
2465 /* collect the possible completions */
2466 static int edit_collect_completions (WEdit
*edit
, long start
,
2467 int word_len
, char *match_expr
, struct selection
*compl, int *num
)
2469 int len
, max_len
= 0, i
, skip
;
2472 /* collect max MAX_WORD_COMPLETIONS completions */
2473 while (*num
< MAX_WORD_COMPLETIONS
) {
2474 /* get next match */
2475 start
= edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2476 edit
->last_byte
, (int (*)(void *, long)) edit_get_byte
,
2483 /* add matched completion if not yet added */
2484 bufpos
= &edit
->buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2486 for (i
= 0; i
< *num
; i
++) {
2487 if (strncmp (&compl[i
].text
[word_len
], &bufpos
[word_len
],
2488 max (len
, compl[i
].len
) - word_len
) == 0) {
2490 break; /* skip it, already added */
2496 compl[*num
].text
= CMalloc (len
+ 1);
2497 compl[*num
].len
= len
;
2498 for (i
= 0; i
< len
; i
++)
2499 compl[*num
].text
[i
] = *(bufpos
+ i
);
2500 compl[*num
].text
[i
] = '\0';
2503 /* note the maximal length needed for the completion dialog */
2511 /* completion dialog callback */
2512 static int compl_callback (Dlg_head
*h
, int key
, int Msg
)
2516 common_dialog_repaint (h
);
2523 static int compllist_callback (void *data
)
2529 /* let the user select its preferred completion */
2530 void edit_completion_dialog (WEdit
*edit
, int max_len
, int word_len
,
2531 struct selection
*compl, int num_compl
)
2533 int start_x
, start_y
, offset
, i
;
2535 Dlg_head
*compl_dlg
;
2536 WListbox
*compl_list
;
2537 unsigned int compl_dlg_h
; /* completion dialog height */
2538 unsigned int compl_dlg_w
; /* completion dialog width */
2540 /* calculate the dialog metrics */
2541 compl_dlg_h
= num_compl
+ 2;
2542 compl_dlg_w
= max_len
+ 4;
2543 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2544 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2548 if (compl_dlg_w
> COLS
)
2550 if (compl_dlg_h
> LINES
- 2)
2551 compl_dlg_h
= LINES
- 2;
2553 offset
= start_x
+ compl_dlg_w
- COLS
;
2556 offset
= start_y
+ compl_dlg_h
- LINES
;
2558 start_y
-= (offset
+ 1);
2560 /* create the dialog */
2561 compl_dlg
= create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2562 dialog_colors
, compl_callback
, "[Word Completion]", "complete_word",
2565 /* create the listbox */
2566 compl_list
= listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, 0,
2567 compllist_callback
, NULL
);
2569 /* add the dialog */
2570 add_widget (compl_dlg
, compl_list
);
2572 /* fill the listbox with the completions */
2573 for (i
= 0; i
< num_compl
; i
++)
2574 listbox_add_item (compl_list
, 0, 0, compl[i
].text
, NULL
);
2576 /* pop up the dialog */
2577 run_dlg (compl_dlg
);
2579 /* apply the choosen completion */
2580 if (compl_dlg
->ret_value
== B_ENTER
) {
2581 listbox_get_current (compl_list
, &curr
, NULL
);
2583 for (curr
+= word_len
; *curr
; curr
++)
2584 edit_insert (edit
, *curr
);
2587 /* destroy dialog before return */
2588 destroy_dlg (compl_dlg
);
2592 /* complete current word using regular expression search */
2593 /* backwards beginning at current cursor position */
2594 void edit_complete_word_cmd (WEdit
*edit
)
2596 int word_len
= 0, i
, num_compl
= 0, max_len
;
2597 long word_start
= 0;
2599 char match_expr
[MAX_REPL_LEN
];
2600 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2602 /* don't want to disturb another search */
2603 int old_rs
= replace_scanf
;
2604 int old_rb
= replace_backwards
;
2605 int old_rr
= replace_regexp
;
2606 int old_rw
= replace_whole
;
2607 int old_rc
= replace_case
;
2609 /* search start of word to be completed */
2610 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2613 /* prepare match expression */
2614 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2615 [word_start
& M_EDIT_BUF_SIZE
];
2616 strncpy (match_expr
, bufpos
, word_len
);
2617 match_expr
[word_len
] = '\0';
2618 strcat (match_expr
, "[a-zA-Z_0-9]+");
2620 /* init search: backward, regexp, whole word, case sensitive */
2621 edit_set_search_parameters (0, 1, 1, 1, 1);
2623 /* collect the possible completions */
2624 /* start search from curs1 down to begin of file */
2625 max_len
= edit_collect_completions (edit
, word_start
, word_len
,
2626 match_expr
, (struct selection
*) &compl, &num_compl
);
2628 if (num_compl
> 0) {
2629 /* insert completed word if there is only one match */
2630 if (num_compl
== 1) {
2631 for (i
= word_len
; i
< compl[0].len
; i
++)
2632 edit_insert (edit
, *(compl[0].text
+ i
));
2634 /* more than one possible completion => ask the user */
2636 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2637 /* !!! pressed again the selection dialog pops up, but that !!! */
2638 /* !!! seems to require a further internal state !!! */
2641 /* let the user select the preferred completion */
2642 edit_completion_dialog (edit
, max_len
, word_len
,
2643 (struct selection
*) &compl, num_compl
);
2647 /* release memory before return */
2648 for (i
= 0; i
< num_compl
; i
++)
2649 free (compl[i
].text
);
2651 /* restore search parameters */
2652 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);