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 */
467 raw_callback (struct Dlg_head
*h
, int key
, int Msg
)
475 return default_dlg_callback (h
, key
, Msg
);;
478 /* gets a raw key from the keyboard. Passing cancel = 1 draws
479 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
480 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
481 and Esc are cannot returned */
483 edit_raw_key_query (char *heading
, char *query
, int cancel
)
485 int w
= strlen (query
) + 7;
486 struct Dlg_head
*raw_dlg
=
487 create_dlg (0, 0, 7, w
, dialog_colors
, raw_callback
,
489 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
492 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
493 _("Cancel"), 0, 0, 0));
494 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
, 0));
496 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
498 w
= raw_dlg
->ret_value
;
499 destroy_dlg (raw_dlg
);
501 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
509 /* creates a macro file if it doesn't exist */
510 static FILE *edit_open_macro_file (const char *r
)
514 filename
= catstrs (home_dir
, MACRO_FILE
, 0);
515 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
518 return fopen (filename
, r
);
521 #define MAX_MACROS 1024
522 static int saved_macro
[MAX_MACROS
+ 1];
523 static int saved_macros_loaded
= 0;
526 This is just to stop the macro file be loaded over and over for keys
527 that aren't defined to anything. On slow systems this could be annoying.
529 int macro_exists (int k
)
532 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
533 if (saved_macro
[i
] == k
)
538 /* returns 1 on error */
539 int edit_delete_macro (WEdit
* edit
, int k
)
541 struct macro macro
[MAX_MACRO_LENGTH
];
545 if (saved_macros_loaded
)
546 if ((j
= macro_exists (k
)) < 0)
548 g
= fopen (catstrs (home_dir
, TEMP_FILE
, 0), "w");
550 /* This heads the delete macro error dialog box */
551 edit_error_dialog (_(" Delete macro "),
552 /* 'Open' = load temp file */
553 get_sys_error (_(" Error trying to open temp file ")));
556 f
= edit_open_macro_file ("r");
558 /* This heads the delete macro error dialog box */
559 edit_error_dialog (_(" Delete macro "),
560 /* 'Open' = load temp file */
561 get_sys_error (_(" Error trying to open macro file ")));
566 n
= fscanf (f
, ("key '%d 0': "), &s
);
570 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
574 fprintf (g
, ("key '%d 0': "), s
);
575 for (i
= 0; i
< n
; i
++)
576 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
582 if (rename (catstrs (home_dir
, TEMP_FILE
, 0), catstrs (home_dir
, MACRO_FILE
, 0)) == -1) {
583 /* This heads the delete macro error dialog box */
584 edit_error_dialog (_(" Delete macro "),
585 get_sys_error (_(" Error trying to overwrite macro file ")));
588 if (saved_macros_loaded
)
589 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
593 /* returns 0 on error */
594 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
599 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
600 /* This heads the 'Macro' dialog box */
601 s
= edit_raw_key_query (_(" Macro "),
602 /* Input line for a single key press follows the ':' */
603 _(" Press the macro's new hotkey: "), 1);
604 edit
->force
|= REDRAW_COMPLETELY
;
606 if (edit_delete_macro (edit
, s
))
608 f
= edit_open_macro_file ("a+");
610 fprintf (f
, ("key '%d 0': "), s
);
611 for (i
= 0; i
< n
; i
++)
612 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
615 if (saved_macros_loaded
) {
616 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
621 /* This heads the 'Save Macro' dialog box */
622 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
627 void edit_delete_macro_cmd (WEdit
* edit
)
631 command
= edit_raw_key_query (_ (" Delete Macro "),
632 _ (" Press macro hotkey: "), 1);
637 edit_delete_macro (edit
, command
);
640 /* return 0 on error */
641 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
644 int s
, i
= 0, found
= 0;
646 if (saved_macros_loaded
)
647 if (macro_exists (k
) < 0)
650 if ((f
= edit_open_macro_file ("r"))) {
654 u
= fscanf (f
, ("key '%d 0': "), &s
);
657 if (!saved_macros_loaded
)
658 saved_macro
[i
++] = s
;
661 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
664 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
669 } while (!found
|| !saved_macros_loaded
);
670 if (!saved_macros_loaded
) {
672 saved_macros_loaded
= 1;
677 /* This heads the 'Load Macro' dialog box */
678 edit_error_dialog (_(" Load macro "),
679 get_sys_error (_(" Error trying to open macro file ")));
683 /* }}} Macro stuff starts here */
685 /* returns 1 on success */
686 int edit_save_confirm_cmd (WEdit
* edit
)
690 if (edit_confirm_save
) {
691 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", 0);
692 /* Buttons to 'Confirm save file' query */
693 if (edit_query_dialog2 (_(" Save file "), f
, _("Save"), _("Cancel")))
696 return edit_save_cmd (edit
);
700 /* returns 1 on success */
701 int edit_save_cmd (WEdit
* edit
)
703 if (!edit_save_file (edit
, catstrs (edit
->dir
, edit
->filename
, 0)))
704 return edit_save_as_cmd (edit
);
705 edit
->force
|= REDRAW_COMPLETELY
;
707 edit
->delete_file
= 0;
713 /* returns 1 on success */
714 int edit_new_cmd (WEdit
* edit
)
716 if (edit
->modified
) {
717 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
718 edit
->force
|= REDRAW_COMPLETELY
;
722 edit
->force
|= REDRAW_COMPLETELY
;
724 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
727 /* returns 1 on error */
728 int edit_load_file_from_filename (WEdit
* edit
, char *exp
)
730 if (!edit_reload (edit
, exp
, 0, "", 0))
732 edit_split_filename (edit
, exp
);
737 int edit_load_cmd (WEdit
* edit
)
741 if (edit
->modified
) {
742 if (edit_query_dialog2 (_ (" Warning "), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
743 edit
->force
|= REDRAW_COMPLETELY
;
748 exp
= edit_get_load_file (edit
->dir
, edit
->filename
, _ (" Load "));
752 edit_load_file_from_filename (edit
, exp
);
755 edit
->force
|= REDRAW_COMPLETELY
;
760 if mark2 is -1 then marking is from mark1 to the cursor.
761 Otherwise its between the markers. This handles this.
762 Returns 1 if no text is marked.
764 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
766 if (edit
->mark1
!= edit
->mark2
) {
767 if (edit
->mark2
>= 0) {
768 *start_mark
= min (edit
->mark1
, edit
->mark2
);
769 *end_mark
= max (edit
->mark1
, edit
->mark2
);
771 *start_mark
= min (edit
->mark1
, edit
->curs1
);
772 *end_mark
= max (edit
->mark1
, edit
->curs1
);
773 edit
->column2
= edit
->curs_col
;
777 *start_mark
= *end_mark
= 0;
778 edit
->column2
= edit
->column1
= 0;
783 #define space_width 1
785 void edit_insert_column_of_text (WEdit
* edit
, unsigned char *data
, int size
, int width
)
789 cursor
= edit
->curs1
;
790 col
= edit_get_col (edit
);
791 for (i
= 0; i
< size
; i
++) {
792 if (data
[i
] == '\n') { /* fill in and move to next line */
795 if (edit_get_byte (edit
, edit
->curs1
) != '\n') {
796 l
= width
- (edit_get_col (edit
) - col
);
798 edit_insert (edit
, ' ');
802 for (p
= edit
->curs1
;; p
++) {
803 if (p
== edit
->last_byte
)
804 edit_insert_ahead (edit
, '\n');
805 if (edit_get_byte (edit
, p
) == '\n') {
810 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->curs1
);
811 l
= col
- edit_get_col (edit
);
812 while (l
>= space_width
) {
813 edit_insert (edit
, ' ');
818 edit_insert (edit
, data
[i
]);
820 edit_cursor_move (edit
, cursor
- edit
->curs1
);
824 void edit_block_copy_cmd (WEdit
* edit
)
826 long start_mark
, end_mark
, current
= edit
->curs1
;
828 unsigned char *copy_buf
;
830 edit_update_curs_col (edit
);
832 if (eval_marks (edit
, &start_mark
, &end_mark
))
834 if (column_highlighting
)
835 if ((x
>= edit
->column1
&& x
< edit
->column2
) || (x
> edit
->column2
&& x
<= edit
->column1
))
838 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
840 /* all that gets pushed are deletes hence little space is used on the stack */
842 edit_push_markers (edit
);
844 if (column_highlighting
) {
845 edit_insert_column_of_text (edit
, copy_buf
, size
, abs (edit
->column2
- edit
->column1
));
848 edit_insert_ahead (edit
, copy_buf
[size
]);
852 edit_scroll_screen_over_cursor (edit
);
854 if (column_highlighting
) {
855 edit_set_markers (edit
, 0, 0, 0, 0);
856 edit_push_action (edit
, COLUMN_ON
);
857 column_highlighting
= 0;
858 } else if (start_mark
< current
&& end_mark
> current
)
859 edit_set_markers (edit
, start_mark
, end_mark
+ end_mark
- start_mark
, 0, 0);
861 edit
->force
|= REDRAW_PAGE
;
865 void edit_block_move_cmd (WEdit
* edit
)
869 unsigned char *copy_buf
;
870 long start_mark
, end_mark
;
874 if (eval_marks (edit
, &start_mark
, &end_mark
))
876 if (column_highlighting
) {
877 edit_update_curs_col (edit
);
879 if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
880 if ((x
> edit
->column1
&& x
< edit
->column2
) || (x
> edit
->column2
&& x
< edit
->column1
))
882 } else if (start_mark
<= edit
->curs1
&& end_mark
>= edit
->curs1
)
885 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
886 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ ("Continue"), _ ("Cancel")))
889 edit_push_markers (edit
);
890 current
= edit
->curs1
;
891 if (column_highlighting
) {
892 int size
, c1
, c2
, line
;
893 line
= edit
->curs_line
;
895 edit_mark_cmd (edit
, 0);
896 c1
= min (edit
->column1
, edit
->column2
);
897 c2
= max (edit
->column1
, edit
->column2
);
898 copy_buf
= edit_get_block (edit
, start_mark
, end_mark
, &size
);
900 edit_block_delete_cmd (edit
);
903 edit_move_to_line (edit
, line
);
904 edit_cursor_move (edit
, edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), x
, 0) - edit
->curs1
);
905 edit_insert_column_of_text (edit
, copy_buf
, size
, c2
- c1
);
907 line
= edit
->curs_line
;
908 edit_update_curs_col (edit
);
910 edit_block_delete_cmd (edit
);
911 edit_move_to_line (edit
, line
);
912 edit_cursor_move (edit
, edit_move_forward3 (edit
, edit_bol (edit
, edit
->curs1
), x
, 0) - edit
->curs1
);
914 edit_set_markers (edit
, 0, 0, 0, 0);
915 edit_push_action (edit
, COLUMN_ON
);
916 column_highlighting
= 0;
918 copy_buf
= malloc (end_mark
- start_mark
);
919 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
920 edit_scroll_screen_over_cursor (edit
);
922 while (count
< end_mark
) {
923 copy_buf
[end_mark
- count
- 1] = edit_delete (edit
);
926 edit_scroll_screen_over_cursor (edit
);
927 edit_cursor_move (edit
, current
- edit
->curs1
- (((current
- edit
->curs1
) > 0) ? end_mark
- start_mark
: 0));
928 edit_scroll_screen_over_cursor (edit
);
929 while (count
-- > start_mark
)
930 edit_insert_ahead (edit
, copy_buf
[end_mark
- count
- 1]);
931 edit_set_markers (edit
, edit
->curs1
, edit
->curs1
+ end_mark
- start_mark
, 0, 0);
933 edit_scroll_screen_over_cursor (edit
);
935 edit
->force
|= REDRAW_PAGE
;
938 void edit_cursor_to_bol (WEdit
* edit
);
940 void edit_delete_column_of_text (WEdit
* edit
)
942 long p
, q
, r
, m1
, m2
;
946 eval_marks (edit
, &m1
, &m2
);
947 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
948 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
949 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
955 r
= edit_bol (edit
, edit
->curs1
);
956 p
= edit_move_forward3 (edit
, r
, b
, 0);
957 q
= edit_move_forward3 (edit
, r
, c
, 0);
962 edit_cursor_move (edit
, p
- edit
->curs1
);
963 while (q
> p
) { /* delete line between margins */
964 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
968 if (n
) /* move to next line except on the last delete */
969 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
973 /* if success return 0 */
974 int edit_block_delete (WEdit
* edit
)
977 long start_mark
, end_mark
;
978 if (eval_marks (edit
, &start_mark
, &end_mark
))
980 if (column_highlighting
&& edit
->mark2
< 0)
981 edit_mark_cmd (edit
, 0);
982 if ((end_mark
- start_mark
) > option_max_undo
/ 2)
983 /* Warning message with a query to continue or cancel the operation */
984 if (edit_query_dialog2 (_ (" Warning "), _ (" Block is large, you may not be able to undo this action. "), _ (" Continue "), _ (" Cancel ")))
986 edit_push_markers (edit
);
987 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
988 edit_scroll_screen_over_cursor (edit
);
990 if (start_mark
< end_mark
) {
991 if (column_highlighting
) {
993 edit_mark_cmd (edit
, 0);
994 edit_delete_column_of_text (edit
);
996 while (count
< end_mark
) {
1002 edit_set_markers (edit
, 0, 0, 0, 0);
1003 edit
->force
|= REDRAW_PAGE
;
1007 /* returns 1 if canceelled by user */
1008 int edit_block_delete_cmd (WEdit
* edit
)
1010 long start_mark
, end_mark
;
1011 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1012 edit_delete_line (edit
);
1015 return edit_block_delete (edit
);
1019 #define INPUT_INDEX 9
1020 #define SEARCH_DLG_WIDTH 58
1021 #define SEARCH_DLG_HEIGHT 10
1022 #define REPLACE_DLG_WIDTH 58
1023 #define REPLACE_DLG_HEIGHT 15
1024 #define CONFIRM_DLG_WIDTH 79
1025 #define CONFIRM_DLG_HEIGTH 6
1026 #define B_REPLACE_ALL B_USER+1
1027 #define B_REPLACE_ONE B_USER+2
1028 #define B_SKIP_REPLACE B_USER+3
1030 int edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1032 QuickWidget quick_widgets
[] =
1034 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1035 0, B_CANCEL
, 0, 0, NULL
},
1036 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("o&Ne"),
1037 0, B_REPLACE_ONE
, 0, 0, NULL
},
1038 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("al&L"),
1039 0, B_REPLACE_ALL
, 0, 0, NULL
},
1040 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1041 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1042 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1043 0, B_ENTER
, 0, 0, NULL
},
1044 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1049 char *msg
= _(" Replace with: ");
1051 quick_widgets
[5].text
= catstrs (msg
, replace_text
, 0);
1054 convert_to_display (quick_widgets
[5].text
+ strlen (msg
));
1056 quick_widgets
[5].text
= catstrs (_ (" Replace with: "), replace_text
, 0);
1057 #endif /* !HAVE_CHARSET */
1060 QuickDialog Quick_input
=
1061 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1062 "[Input Line Keys]", 0 /*quick_widgets */ };
1064 Quick_input
.widgets
= quick_widgets
;
1066 Quick_input
.xpos
= xpos
;
1068 /* Sometimes menu can hide replaced text. I don't like it */
1070 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1071 ypos
-= CONFIRM_DLG_HEIGTH
;
1073 Quick_input
.ypos
= ypos
;
1074 return quick_dialog (&Quick_input
);
1078 void edit_replace_dialog (WEdit
* edit
, char **search_text
, char **replace_text
, char **arg_order
)
1080 int treplace_scanf
= replace_scanf
;
1081 int treplace_regexp
= replace_regexp
;
1082 int treplace_all
= replace_all
;
1083 int treplace_prompt
= replace_prompt
;
1084 int treplace_backwards
= replace_backwards
;
1085 int treplace_whole
= replace_whole
;
1086 int treplace_case
= replace_case
;
1088 QuickWidget quick_widgets
[] =
1090 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1092 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
1094 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1096 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1098 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pr&Ompt on replace"), 0, 0,
1100 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1102 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1104 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1106 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1108 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1110 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1112 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1114 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1116 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1118 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1122 quick_widgets
[2].result
= &treplace_scanf
;
1123 quick_widgets
[3].result
= &treplace_all
;
1124 quick_widgets
[4].result
= &treplace_prompt
;
1125 quick_widgets
[5].result
= &treplace_backwards
;
1126 quick_widgets
[6].result
= &treplace_regexp
;
1127 quick_widgets
[7].result
= &treplace_whole
;
1128 quick_widgets
[8].result
= &treplace_case
;
1129 quick_widgets
[9].str_result
= arg_order
;
1130 quick_widgets
[9].text
= *arg_order
;
1131 quick_widgets
[11].str_result
= replace_text
;
1132 quick_widgets
[11].text
= *replace_text
;
1133 quick_widgets
[13].str_result
= search_text
;
1134 quick_widgets
[13].text
= *search_text
;
1136 QuickDialog Quick_input
=
1137 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1138 "[Input Line Keys]", 0 /*quick_widgets */ };
1140 Quick_input
.widgets
= quick_widgets
;
1142 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1143 replace_scanf
= treplace_scanf
;
1144 replace_backwards
= treplace_backwards
;
1145 replace_regexp
= treplace_regexp
;
1146 replace_all
= treplace_all
;
1147 replace_prompt
= treplace_prompt
;
1148 replace_whole
= treplace_whole
;
1149 replace_case
= treplace_case
;
1153 *replace_text
= NULL
;
1154 *search_text
= NULL
;
1161 void edit_search_dialog (WEdit
* edit
, char **search_text
)
1163 int treplace_scanf
= replace_scanf
;
1164 int treplace_regexp
= replace_regexp
;
1165 int treplace_whole
= replace_whole
;
1166 int treplace_case
= replace_case
;
1167 int treplace_backwards
= replace_backwards
;
1169 QuickWidget quick_widgets
[] =
1171 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1173 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
1175 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1177 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1179 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1181 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1183 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1185 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1187 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1191 quick_widgets
[2].result
= &treplace_scanf
;
1192 quick_widgets
[3].result
= &treplace_backwards
;
1193 quick_widgets
[4].result
= &treplace_regexp
;
1194 quick_widgets
[5].result
= &treplace_whole
;
1195 quick_widgets
[6].result
= &treplace_case
;
1196 quick_widgets
[7].str_result
= search_text
;
1197 quick_widgets
[7].text
= *search_text
;
1200 QuickDialog Quick_input
=
1201 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_(" Search "),
1202 "[Input Line Keys]", 0 /*quick_widgets */ };
1204 Quick_input
.widgets
= quick_widgets
;
1206 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1207 replace_scanf
= treplace_scanf
;
1208 replace_backwards
= treplace_backwards
;
1209 replace_regexp
= treplace_regexp
;
1210 replace_whole
= treplace_whole
;
1211 replace_case
= treplace_case
;
1213 *search_text
= NULL
;
1219 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1221 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1222 sargs[4], sargs[5], sargs[6], sargs[7], \
1223 sargs[8], sargs[9], sargs[10], sargs[11], \
1224 sargs[12], sargs[13], sargs[14], sargs[15]
1226 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1227 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1228 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1229 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1232 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1233 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1234 int string_regexp_search (char *pattern
, char *string
, int len
, int match_type
, int match_bol
, int icase
, int *found_len
, void *d
)
1237 static char *old_pattern
= NULL
;
1238 static int old_type
, old_icase
;
1240 static regmatch_t s
[1];
1242 pmatch
= (regmatch_t
*) d
;
1246 if (!old_pattern
|| strcmp (old_pattern
, pattern
) || old_type
!= match_type
|| old_icase
!= icase
) {
1252 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0))) {
1256 old_pattern
= (char *) strdup (pattern
);
1257 old_type
= match_type
;
1260 if (regexec (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
, ((match_bol
|| match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1264 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1265 return (pmatch
[0].rm_so
);
1268 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1269 (and the above) routines to work properly - paul */
1271 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
)
1274 long l
= strlen ((char *) exp
), f
= 0;
1277 for (p
= 0; p
< l
; p
++) /* count conversions... */
1279 if (exp
[++p
] != '%') /* ...except for "%%" */
1282 if (replace_scanf
|| replace_regexp
) {
1285 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1287 replace_scanf
= (!replace_regexp
); /* can't have both */
1291 if (replace_scanf
) {
1292 unsigned char e
[MAX_REPL_LEN
];
1293 if (n
>= NUM_REPL_ARGS
)
1297 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1298 buf
[p
- start
] = (*get_byte
) (data
, p
);
1300 for (p
= 0; exp
[p
] != 0; p
++)
1301 exp
[p
] = my_lower_case (exp
[p
]);
1302 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1303 c
= (*get_byte
) (data
, p
);
1304 buf
[p
- start
] = my_lower_case (c
);
1308 buf
[(q
= p
- start
)] = 0;
1309 strcpy ((char *) e
, (char *) exp
);
1310 strcat ((char *) e
, "%n");
1314 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1315 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1316 if (*((int *) sargs
[n
])) {
1317 *len
= *((int *) sargs
[n
]);
1323 if (q
+ start
< last_byte
) {
1325 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1327 c
= (*get_byte
) (data
, q
+ start
);
1328 buf
[q
] = my_lower_case (c
);
1334 buf
++; /* move the window along */
1335 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1336 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1341 } else { /* regexp matching */
1343 int found_start
, match_bol
, move_win
= 0;
1345 while (start
+ offset
< last_byte
) {
1346 match_bol
= (offset
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1351 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1352 mbuf
[q
] = (*get_byte
) (data
, p
);
1353 if (mbuf
[q
] == '\n')
1362 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, q
, match_normal
, match_bol
, !replace_case
, len
, d
);
1364 if (found_start
<= -2) { /* regcomp/regexec error */
1368 else if (found_start
== -1) /* not found: try next line */
1370 else if (*len
== 0) { /* null pattern: try again at next character */
1377 return (start
+ offset
- q
+ found_start
);
1382 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1383 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1384 q
= strlen ((char *) buf
);
1385 memmove (mbuf
, buf
, q
);
1394 *len
= strlen ((char *) exp
);
1396 for (p
= start
; p
<= last_byte
- l
; p
++) {
1397 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1398 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1399 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1408 for (p
= 0; exp
[p
] != 0; p
++)
1409 exp
[p
] = my_lower_case (exp
[p
]);
1411 for (p
= start
; p
<= last_byte
- l
; p
++) {
1412 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1413 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1414 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1428 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
)
1429 { /*front end to find_string to check for
1434 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1435 if (replace_whole
) {
1436 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1437 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1438 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1446 p
++; /*not a whole word so continue search. */
1451 long edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, void *d
)
1454 if (replace_backwards
) {
1455 while (search_start
>= 0) {
1456 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1457 if (p
== search_start
)
1462 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1467 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1469 #define snprintf(v) { \
1474 sprintf(s,q1,v,&n); \
1478 /* this function uses the sprintf command to do a vprintf */
1479 /* it takes pointers to arguments instead of the arguments themselves */
1480 static int sprintf_p (char *str
, const char *fmt
,...)
1481 __attribute__ ((format (printf
, 2, 3)));
1483 static int sprintf_p (char *str
, const char *fmt
,...)
1487 char *q
, *p
, *s
= str
;
1492 p
= q
= (char *) fmt
;
1494 while ((p
= strchr (p
, '%'))) {
1496 strncpy (s
, q
, n
); /* copy stuff between format specifiers */
1524 strcpy (p1
, itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1527 while (is_digit (*p
))
1534 strcpy (p1
, itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1537 while (is_digit (*p
))
1540 /* flags done, now get argument */
1542 snprintf (va_arg (ap
, char *));
1543 } else if (*p
== 'h') {
1544 if (strchr ("diouxX", *p
))
1545 snprintf (*va_arg (ap
, short *));
1546 } else if (*p
== 'l') {
1548 if (strchr ("diouxX", *p
))
1549 snprintf (*va_arg (ap
, long *));
1550 } else if (strchr ("cdiouxX", *p
)) {
1551 snprintf (*va_arg (ap
, int *));
1552 } else if (*p
== 'L') {
1554 if (strchr ("EefgG", *p
))
1555 snprintf (*va_arg (ap
, double *)); /* should be long double */
1556 } else if (strchr ("EefgG", *p
)) {
1557 snprintf (*va_arg (ap
, double *));
1558 } else if (strchr ("DOU", *p
)) {
1559 snprintf (*va_arg (ap
, long *));
1560 } else if (*p
== 'p') {
1561 snprintf (*va_arg (ap
, void **));
1566 sprintf (s
, q
); /* print trailing leftover */
1567 return s
- str
+ strlen (s
);
1570 static void regexp_error (WEdit
*edit
)
1572 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1573 edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
1576 /* call with edit = 0 before shutdown to close memory leaks */
1577 void edit_replace_cmd (WEdit
* edit
, int again
)
1579 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1580 static char *old1
= NULL
;
1581 static char *old2
= NULL
;
1582 static char *old3
= NULL
;
1587 int replace_continue
;
1588 int treplace_prompt
= 0;
1590 long times_replaced
= 0, last_search
;
1591 int argord
[NUM_REPL_ARGS
];
1608 last_search
= edit
->last_byte
;
1610 edit
->force
|= REDRAW_COMPLETELY
;
1612 exp1
= old1
? old1
: exp1
;
1613 exp2
= old2
? old2
: exp2
;
1614 exp3
= old3
? old3
: exp3
;
1619 exp1
= g_strdup (old1
);
1620 exp2
= g_strdup (old2
);
1621 exp3
= g_strdup (old3
);
1623 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1627 convert_to_display (exp1
);
1629 convert_to_display (exp2
);
1630 #endif /* HAVE_CHARSET */
1632 edit_replace_dialog (edit
, &exp1
, &exp2
, &exp3
);
1636 convert_from_input (exp1
);
1638 convert_from_input (exp2
);
1639 #endif /* HAVE_CHARSET */
1641 treplace_prompt
= replace_prompt
;
1644 if (!exp1
|| !*exp1
) {
1645 edit
->force
= REDRAW_COMPLETELY
;
1660 old1
= g_strdup (exp1
);
1661 old2
= g_strdup (exp2
);
1662 old3
= g_strdup (exp3
);
1667 while ((s
= strchr (exp3
, ' ')))
1668 memmove (s
, s
+ 1, strlen (s
));
1670 for (i
= 0; i
< NUM_REPL_ARGS
; i
++) {
1671 if (s
!= (char *)1 && *s
) {
1673 if ((ord
> 0) && (ord
< NUM_REPL_ARGS
))
1674 argord
[i
] = ord
- 1;
1677 s
= strchr (s
, ',') + 1;
1683 replace_continue
= replace_all
;
1685 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1686 edit
->search_start
--;
1688 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1689 edit
->search_start
++;
1694 new_start
= edit_find (edit
->search_start
, (unsigned char *) exp1
, &len
, last_search
,
1695 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, pmatch
);
1696 if (new_start
== -3) {
1697 regexp_error (edit
);
1700 edit
->search_start
= new_start
;
1701 /*returns negative on not found or error in pattern */
1703 if (edit
->search_start
>= 0) {
1704 edit
->found_start
= edit
->search_start
;
1705 i
= edit
->found_len
= len
;
1707 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1708 edit_scroll_screen_over_cursor (edit
);
1712 if (treplace_prompt
) {
1714 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1716 edit_scroll_downward (edit
, l
);
1718 edit_scroll_upward (edit
, -l
);
1720 edit_scroll_screen_over_cursor (edit
);
1721 edit
->force
|= REDRAW_PAGE
;
1722 edit_render_keypress (edit
);
1724 /*so that undo stops at each query */
1725 edit_push_key_press (edit
);
1727 switch (edit_replace_prompt (edit
, exp2
, /* and prompt 2/3 down */
1728 (edit
->num_widget_columns
- CONFIRM_DLG_WIDTH
)/2,
1729 edit
->num_widget_lines
* 2 / 3)) {
1732 case B_SKIP_REPLACE
:
1736 treplace_prompt
= 0;
1737 replace_continue
= 1;
1740 replace_continue
= 0;
1744 replace_continue
= 0;
1748 if (replace_yes
) { /* delete then insert new */
1749 if (replace_scanf
|| replace_regexp
) {
1750 char repl_str
[MAX_REPL_LEN
+ 2];
1751 if (replace_regexp
) { /* we need to fill in sargs just like with scanf */
1753 for (k
= 1; k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0; k
++) {
1755 t
= (unsigned char *) &sargs
[k
- 1][0];
1756 for (j
= 0; j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
&& j
< 255; j
++, t
++)
1757 *t
= (unsigned char) edit_get_byte (edit
, edit
->search_start
- pmatch
[0].rm_so
+ pmatch
[k
].rm_so
+ j
);
1760 for (; k
<= NUM_REPL_ARGS
; k
++)
1761 sargs
[k
- 1][0] = 0;
1763 if (sprintf_p (repl_str
, exp2
, PRINTF_ARGS
) >= 0) {
1767 while (repl_str
[++i
])
1768 edit_insert (edit
, repl_str
[i
]);
1770 edit_error_dialog (_ (" Replace "),
1771 /* "Invalid regexp string or scanf string" */
1772 _ (" Error in replacement format string. "));
1773 replace_continue
= 0;
1780 edit_insert (edit
, exp2
[i
]);
1782 edit
->found_len
= i
;
1784 /* so that we don't find the same string again */
1785 if (replace_backwards
) {
1786 last_search
= edit
->search_start
;
1787 edit
->search_start
--;
1789 edit
->search_start
+= i
;
1790 last_search
= edit
->last_byte
;
1792 edit_scroll_screen_over_cursor (edit
);
1794 edit
->search_start
= edit
->curs1
; /* try and find from right here for next search */
1795 edit_update_curs_col (edit
);
1797 edit
->force
|= REDRAW_PAGE
;
1798 edit_render_keypress (edit
);
1799 if (times_replaced
) {
1800 message (0, _(" Replace "), _(" %ld replacements made. "), times_replaced
);
1802 edit_message_dialog (_ (" Replace "), _ (" Search string not found "));
1803 replace_continue
= 0;
1805 } while (replace_continue
);
1810 edit
->force
= REDRAW_COMPLETELY
;
1811 edit_scroll_screen_over_cursor (edit
);
1817 void edit_search_cmd (WEdit
* edit
, int again
)
1819 static char *old
= NULL
;
1829 exp
= old
? old
: exp
;
1830 if (again
) { /*ctrl-hotkey for search again. */
1833 exp
= (char *) g_strdup (old
);
1838 convert_to_display (exp
);
1839 #endif /* HAVE_CHARSET */
1841 edit_search_dialog (edit
, &exp
);
1845 convert_from_input (exp
);
1846 #endif /* HAVE_CHARSET */
1848 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1856 old
= (char *) g_strdup (exp
);
1858 if (search_create_bookmark
) {
1859 int found
= 0, books
= 0;
1860 int l
= 0, l_last
= -1;
1863 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1864 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1868 l
+= edit_count_lines (edit
, q
, p
);
1870 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
1877 /* in response to number of bookmarks added because of string being found %d times */
1878 message (0, _(" Search "), _(" %d finds made, %d bookmarks added "), found
, books
);
1880 edit_error_dialog (_ (" Search "), _ (" Search string not found "));
1884 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1885 edit
->search_start
--;
1887 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1888 edit
->search_start
++;
1890 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1891 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1893 if (edit
->search_start
>= 0) {
1894 edit
->found_start
= edit
->search_start
;
1895 edit
->found_len
= len
;
1897 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1898 edit_scroll_screen_over_cursor (edit
);
1899 if (replace_backwards
)
1900 edit
->search_start
--;
1902 edit
->search_start
++;
1903 } else if (edit
->search_start
== -3) {
1904 edit
->search_start
= edit
->curs1
;
1905 regexp_error (edit
);
1907 edit
->search_start
= edit
->curs1
;
1908 edit_error_dialog (_ (" Search "), _ (" Search string not found "));
1914 edit
->force
|= REDRAW_COMPLETELY
;
1915 edit_scroll_screen_over_cursor (edit
);
1919 /* Real edit only */
1920 void edit_quit_cmd (WEdit
* edit
)
1922 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1924 edit
->force
|= REDRAW_COMPLETELY
;
1925 if (edit
->modified
) {
1926 switch (edit_query_dialog3 (_ (" Quit "), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
1928 edit_push_markers (edit
);
1929 edit_set_markers (edit
, 0, 0, 0, 0);
1930 if (!edit_save_cmd (edit
))
1934 if (edit
->delete_file
)
1935 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1942 else if (edit
->delete_file
)
1943 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1944 dlg_stop (edit
->widget
.parent
);
1947 #define TEMP_BUF_LEN 1024
1949 /* returns a null terminated length of text. Result must be free'd */
1950 unsigned char *edit_get_block (WEdit
* edit
, long start
, long finish
, int *l
)
1952 unsigned char *s
, *r
;
1953 r
= s
= malloc (finish
- start
+ 1);
1954 if (column_highlighting
) {
1956 while (start
< finish
) { /* copy from buffer, excluding chars that are out of the column 'margins' */
1958 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0, start
);
1959 c
= edit_get_byte (edit
, start
);
1960 if ((x
>= edit
->column1
&& x
< edit
->column2
)
1961 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
1968 *l
= finish
- start
;
1969 while (start
< finish
)
1970 *s
++ = edit_get_byte (edit
, start
++);
1976 /* save block, returns 1 on success */
1977 int edit_save_block (WEdit
* edit
, const char *filename
, long start
, long finish
)
1981 if ((file
= mc_open ((char *) filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
1984 if (column_highlighting
) {
1985 unsigned char *block
, *p
;
1987 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
1989 r
= mc_write (file
, p
, len
);
1999 len
= finish
- start
;
2000 buf
= malloc (TEMP_BUF_LEN
);
2001 while (start
!= finish
) {
2002 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2003 for (; i
< end
; i
++)
2004 buf
[i
- start
] = edit_get_byte (edit
, i
);
2005 len
-= mc_write (file
, (char *) buf
, end
- start
);
2016 /* copies a block to clipboard file */
2017 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2019 return edit_save_block (edit
, catstrs (home_dir
, CLIP_FILE
, 0), start
, finish
);
2023 void edit_paste_from_history (WEdit
*edit
)
2027 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2029 long start_mark
, end_mark
;
2030 if (eval_marks (edit
, &start_mark
, &end_mark
))
2032 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2033 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2036 edit_mark_cmd (edit
, 1);
2040 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2042 long start_mark
, end_mark
;
2043 if (eval_marks (edit
, &start_mark
, &end_mark
))
2045 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2046 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2049 edit_block_delete_cmd (edit
);
2050 edit_mark_cmd (edit
, 1);
2054 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2056 edit_insert_file (edit
, catstrs (home_dir
, CLIP_FILE
, 0));
2060 void edit_goto_cmd (WEdit
*edit
)
2065 sprintf (s
, "%d", l
);
2066 f
= input_dialog (_(" Goto line "), _(" Enter line: "), l
? s
: "");
2070 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2071 edit_move_to_line (edit
, l
- 1);
2072 edit
->force
|= REDRAW_COMPLETELY
;
2078 /*returns 1 on success */
2079 int edit_save_block_cmd (WEdit
* edit
)
2081 long start_mark
, end_mark
;
2083 if (eval_marks (edit
, &start_mark
, &end_mark
))
2085 exp
= edit_get_save_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Save Block "));
2086 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2092 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2094 edit
->force
|= REDRAW_COMPLETELY
;
2098 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2102 edit
->force
|= REDRAW_COMPLETELY
;
2107 /* returns 1 on success */
2108 int edit_insert_file_cmd (WEdit
* edit
)
2110 char *exp
= edit_get_load_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Insert File "));
2111 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2117 if (edit_insert_file (edit
, exp
)) {
2119 edit
->force
|= REDRAW_COMPLETELY
;
2123 edit_error_dialog (_ (" Insert file "), get_sys_error (_ (" Error trying to insert file. ")));
2127 edit
->force
|= REDRAW_COMPLETELY
;
2131 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2132 int edit_sort_cmd (WEdit
* edit
)
2134 static char *old
= 0;
2136 long start_mark
, end_mark
;
2139 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2140 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2143 edit_save_block (edit
, catstrs (home_dir
, BLOCK_FILE
, 0), start_mark
, end_mark
);
2145 exp
= old
? old
: "";
2147 exp
= input_dialog (_(" Run Sort "),
2148 _(" Enter sort options (see manpage) separated by whitespace: "), exp
);
2156 e
= system (catstrs (" sort ", exp
, " ", home_dir
, BLOCK_FILE
, " > ", home_dir
, TEMP_FILE
, 0));
2158 if (e
== -1 || e
== 127) {
2159 edit_error_dialog (_(" Sort "),
2160 get_sys_error (_(" Error trying to execute sort command ")));
2163 sprintf (q
, "%d ", e
);
2164 edit_error_dialog (_(" Sort "),
2165 catstrs (_(" Sort returned non-zero: "), q
, 0));
2170 edit
->force
|= REDRAW_COMPLETELY
;
2172 if (edit_block_delete_cmd (edit
))
2174 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, 0));
2178 /* if block is 1, a block must be highlighted and the shell command
2179 processes it. If block is 0 the shell command is a straight system
2180 command, that just produces some output which is to be inserted */
2182 edit_block_process_cmd (WEdit
* edit
, const char *shell_cmd
, int block
)
2184 long start_mark
, end_mark
;
2186 FILE *script_home
= NULL
;
2187 FILE *script_src
= NULL
;
2188 FILE *block_file
= NULL
;
2193 o
= catstrs (mc_home
, shell_cmd
, 0); /* original source script */
2194 h
= catstrs (home_dir
, EDIT_DIR
, shell_cmd
, 0); /* home script */
2195 b
= catstrs (home_dir
, BLOCK_FILE
, 0); /* block file */
2197 if (!(script_home
= fopen (h
, "r"))) {
2198 if (!(script_home
= fopen (h
, "w"))) {
2199 edit_error_dialog ("", get_sys_error (catstrs
2201 ("Error creating script:"),
2205 if (!(script_src
= fopen (o
, "r"))) {
2206 fclose (script_home
);
2208 edit_error_dialog ("", get_sys_error (catstrs
2209 (_("Error reading script:"),
2213 while (fgets (buf
, sizeof (buf
), script_src
))
2214 fputs (buf
, script_home
);
2215 if (fclose (script_home
)) {
2216 edit_error_dialog ("", get_sys_error (catstrs
2218 ("Error closing script:"),
2223 edit_error_dialog ("", get_sys_error (catstrs
2224 (_("Script created:"), h
,
2230 if (block
) { /* for marked block run indent formatter */
2231 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2232 edit_error_dialog (_("Process block"),
2234 (" You must first highlight a block of text. "));
2237 edit_save_block (edit
, b
, start_mark
, end_mark
);
2241 * Initial space is to avoid polluting bash history.
2243 * $1 - name of the edited file (to check its extention etc).
2244 * $2 - file containing the current block.
2245 * $3 - file where error messages should be put
2246 * (for compatibility with old scripts).
2248 system (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2249 edit
->filename
, " ", home_dir
, BLOCK_FILE
,
2250 " /dev/null", NULL
));
2254 * No block selected, just execute the command for the file.
2256 * $1 - name of the edited file.
2258 system (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2259 edit
->filename
, NULL
));
2262 close_error_pipe (0, 0);
2264 edit_refresh_cmd (edit
);
2265 edit
->force
|= REDRAW_COMPLETELY
;
2267 /* insert result block */
2269 if (edit_block_delete_cmd (edit
))
2271 edit_insert_file (edit
, b
);
2272 if ((block_file
= fopen (b
, "w")))
2273 fclose (block_file
);
2280 /* prints at the cursor */
2281 /* returns the number of chars printed */
2282 int edit_print_string (WEdit
* e
, const char *s
)
2286 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2287 e
->force
|= REDRAW_COMPLETELY
;
2288 edit_update_screen (e
);
2292 int edit_printf (WEdit
* e
, const char *fmt
, ...)
2298 g_vsnprintf (s
, sizeof (s
), fmt
, pa
);
2299 i
= edit_print_string (e
, s
);
2304 /* FIXME: does this function break NT_OS2 ? */
2306 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2311 s
= g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject
, cc
, to
);
2320 for (i
= 0; i
< edit
->last_byte
; i
++)
2321 fputc (edit_get_byte (edit
, i
), p
);
2326 #define MAIL_DLG_HEIGHT 12
2328 void edit_mail_dialog (WEdit
* edit
)
2331 char *tmail_subject
;
2334 static char *mail_cc_last
= 0;
2335 static char *mail_subject_last
= 0;
2336 static char *mail_to_last
= 0;
2338 QuickDialog Quick_input
=
2339 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2340 "[Input Line Keys]", 0};
2342 QuickWidget quick_widgets
[] =
2344 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2346 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&Ok"), 0, B_ENTER
, 0,
2348 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2349 0, "mail-dlg-input"},
2350 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2352 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2353 0, "mail-dlg-input-2"},
2354 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2356 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2357 0, "mail-dlg-input-3"},
2358 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2360 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2364 quick_widgets
[2].str_result
= &tmail_cc
;
2365 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2366 quick_widgets
[4].str_result
= &tmail_subject
;
2367 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2368 quick_widgets
[6].str_result
= &tmail_to
;
2369 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2371 Quick_input
.widgets
= quick_widgets
;
2373 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2375 g_free (mail_cc_last
);
2376 if (mail_subject_last
)
2377 g_free (mail_subject_last
);
2379 g_free (mail_to_last
);
2380 mail_cc_last
= *(quick_widgets
[2].str_result
);
2381 mail_subject_last
= *(quick_widgets
[4].str_result
);
2382 mail_to_last
= *(quick_widgets
[6].str_result
);
2383 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2388 /*******************/
2389 /* Word Completion */
2390 /*******************/
2393 /* find first character of current word */
2394 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2398 /* return if at begin of file */
2399 if (edit
->curs1
<= 0)
2402 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2403 /* return if not at end or in word */
2404 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2407 /* search start of word to be completed */
2409 /* return if at begin of file */
2410 if (edit
->curs1
- i
< 0)
2414 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2416 if (!(isalnum (c
) || c
== '_')) {
2417 /* return if word starts with digit */
2421 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2431 /* (re)set search parameters to the given values */
2432 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2435 replace_backwards
= rb
;
2436 replace_regexp
= rr
;
2442 const static int MAX_WORD_COMPLETIONS
= 100; /* in listbox */
2445 /* collect the possible completions */
2446 static int edit_collect_completions (WEdit
*edit
, long start
,
2447 int word_len
, char *match_expr
, struct selection
*compl, int *num
)
2449 int len
, max_len
= 0, i
, skip
;
2452 /* collect max MAX_WORD_COMPLETIONS completions */
2453 while (*num
< MAX_WORD_COMPLETIONS
) {
2454 /* get next match */
2455 start
= edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2456 edit
->last_byte
, (int (*)(void *, long)) edit_get_byte
,
2463 /* add matched completion if not yet added */
2464 bufpos
= &edit
->buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2466 for (i
= 0; i
< *num
; i
++) {
2467 if (strncmp (&compl[i
].text
[word_len
], &bufpos
[word_len
],
2468 max (len
, compl[i
].len
) - word_len
) == 0) {
2470 break; /* skip it, already added */
2476 compl[*num
].text
= CMalloc (len
+ 1);
2477 compl[*num
].len
= len
;
2478 for (i
= 0; i
< len
; i
++)
2479 compl[*num
].text
[i
] = *(bufpos
+ i
);
2480 compl[*num
].text
[i
] = '\0';
2483 /* note the maximal length needed for the completion dialog */
2491 static int compllist_callback (void *data
)
2497 /* let the user select its preferred completion */
2498 void edit_completion_dialog (WEdit
*edit
, int max_len
, int word_len
,
2499 struct selection
*compl, int num_compl
)
2501 int start_x
, start_y
, offset
, i
;
2503 Dlg_head
*compl_dlg
;
2504 WListbox
*compl_list
;
2505 unsigned int compl_dlg_h
; /* completion dialog height */
2506 unsigned int compl_dlg_w
; /* completion dialog width */
2508 /* calculate the dialog metrics */
2509 compl_dlg_h
= num_compl
+ 2;
2510 compl_dlg_w
= max_len
+ 4;
2511 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2512 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2516 if (compl_dlg_w
> COLS
)
2518 if (compl_dlg_h
> LINES
- 2)
2519 compl_dlg_h
= LINES
- 2;
2521 offset
= start_x
+ compl_dlg_w
- COLS
;
2524 offset
= start_y
+ compl_dlg_h
- LINES
;
2526 start_y
-= (offset
+ 1);
2528 /* create the dialog */
2529 compl_dlg
= create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2530 dialog_colors
, NULL
, "[Completion]", NULL
,
2533 /* create the listbox */
2534 compl_list
= listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, 0,
2535 compllist_callback
, NULL
);
2537 /* add the dialog */
2538 add_widget (compl_dlg
, compl_list
);
2540 /* fill the listbox with the completions */
2541 for (i
= 0; i
< num_compl
; i
++)
2542 listbox_add_item (compl_list
, 0, 0, compl[i
].text
, NULL
);
2544 /* pop up the dialog */
2545 run_dlg (compl_dlg
);
2547 /* apply the choosen completion */
2548 if (compl_dlg
->ret_value
== B_ENTER
) {
2549 listbox_get_current (compl_list
, &curr
, NULL
);
2551 for (curr
+= word_len
; *curr
; curr
++)
2552 edit_insert (edit
, *curr
);
2555 /* destroy dialog before return */
2556 destroy_dlg (compl_dlg
);
2560 /* complete current word using regular expression search */
2561 /* backwards beginning at current cursor position */
2562 void edit_complete_word_cmd (WEdit
*edit
)
2564 int word_len
= 0, i
, num_compl
= 0, max_len
;
2565 long word_start
= 0;
2567 char match_expr
[MAX_REPL_LEN
];
2568 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2570 /* don't want to disturb another search */
2571 int old_rs
= replace_scanf
;
2572 int old_rb
= replace_backwards
;
2573 int old_rr
= replace_regexp
;
2574 int old_rw
= replace_whole
;
2575 int old_rc
= replace_case
;
2577 /* search start of word to be completed */
2578 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2581 /* prepare match expression */
2582 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2583 [word_start
& M_EDIT_BUF_SIZE
];
2584 strncpy (match_expr
, bufpos
, word_len
);
2585 match_expr
[word_len
] = '\0';
2586 strcat (match_expr
, "[a-zA-Z_0-9]+");
2588 /* init search: backward, regexp, whole word, case sensitive */
2589 edit_set_search_parameters (0, 1, 1, 1, 1);
2591 /* collect the possible completions */
2592 /* start search from curs1 down to begin of file */
2593 max_len
= edit_collect_completions (edit
, word_start
, word_len
,
2594 match_expr
, (struct selection
*) &compl, &num_compl
);
2596 if (num_compl
> 0) {
2597 /* insert completed word if there is only one match */
2598 if (num_compl
== 1) {
2599 for (i
= word_len
; i
< compl[0].len
; i
++)
2600 edit_insert (edit
, *(compl[0].text
+ i
));
2602 /* more than one possible completion => ask the user */
2604 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2605 /* !!! pressed again the selection dialog pops up, but that !!! */
2606 /* !!! seems to require a further internal state !!! */
2609 /* let the user select the preferred completion */
2610 edit_completion_dialog (edit
, max_len
, word_len
,
2611 (struct selection
*) &compl, num_compl
);
2615 /* release memory before return */
2616 for (i
= 0; i
< num_compl
; i
++)
2617 free (compl[i
].text
);
2619 /* restore search parameters */
2620 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);