1 /* editor high level editing commands.
3 Copyright (C) 1996, 1997 the Free Software Foundation
5 Authors: 1996, 1997 Paul Sheer
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
30 #include "editcmddef.h"
32 #include "src/color.h" /* dialog_colors */
33 #include "src/tty.h" /* LINES */
34 #include "src/widget.h" /* listbox_new() */
35 #include "src/main.h" /* mc_home */
36 #include "src/help.h" /* interactive_display() */
37 #include "src/key.h" /* XCTRL */
38 #include "src/wtools.h" /* message() */
39 #include "src/charsets.h"
43 /* search and replace: */
44 int replace_scanf
= 0;
45 int replace_regexp
= 0;
47 int replace_prompt
= 1;
48 int replace_whole
= 0;
50 int replace_backwards
= 0;
51 int search_create_bookmark
= 0;
53 /* queries on a save */
54 int edit_confirm_save
= 1;
56 #define NUM_REPL_ARGS 64
57 #define MAX_REPL_LEN 1024
59 static inline int my_lower_case (int c
)
61 return tolower(c
& 0xFF);
64 char *strcasechr (const unsigned char *s
, int c
)
66 for (c
= my_lower_case (c
); my_lower_case ((int) *s
) != c
; ++s
)
74 static void *memmove (void *dest
, const void *src
, size_t n
)
84 t
= (char *) dest
+ n
;
91 #endif /* !HAVE_MEMMOVE */
93 /* #define itoa MY_itoa <---- this line is now in edit.h */
103 } while ((i
= i
/ 10));
109 /* Temporary strings */
110 static char *stacked
[16];
113 This joins strings end on end and allocates memory for the result.
114 The result is later automatically free'd and must not be free'd
117 char *catstrs (const char *first
,...)
127 len
= strlen (first
);
128 va_start (ap
, first
);
130 while ((data
= va_arg (ap
, char *)) != 0)
131 len
+= strlen (data
);
138 stacked
[i
] = g_malloc (len
);
140 va_start (ap
, first
);
141 strcpy (stacked
[i
], first
);
142 while ((data
= va_arg (ap
, char *)) != 0)
143 strcat (stacked
[i
], data
);
149 /* Free temporary strings */
154 for (i
= 0; i
< sizeof(stacked
) / sizeof(stacked
[0]); i
++) {
160 void edit_help_cmd (WEdit
* edit
)
162 interactive_display (NULL
, "[Internal File Editor]");
163 edit
->force
|= REDRAW_COMPLETELY
;
166 void edit_refresh_cmd (WEdit
* edit
)
174 edit_get_syntax_color (edit
, -1, &color
);
177 #endif /* !HAVE_SLANG */
182 /* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
185 /* If 0 (quick save) then a) create/truncate <filename> file,
186 b) save to <filename>;
187 if 1 (safe save) then a) save to <tempnam>,
188 b) rename <tempnam> to <filename>;
189 if 2 (do backups) then a) save to <tempnam>,
190 b) rename <filename> to <filename.backup_ext>,
191 c) rename <tempnam> to <filename>. */
193 /* returns 0 on error */
194 int edit_save_file (WEdit
* edit
, const char *filename
)
199 int this_save_mode
, fd
;
206 if ((fd
= mc_open (filename
, O_WRONLY
| O_BINARY
)) == -1) {
208 * The file does not exists yet, so no safe save or
209 * backup are necessary.
214 this_save_mode
= option_save_mode
;
217 if (this_save_mode
> 0) {
218 char *savedir
, *slashpos
, *saveprefix
;
219 slashpos
= strrchr (filename
, PATH_SEP
);
221 savedir
= (char *) strdup (filename
);
222 savedir
[slashpos
- filename
+ 1] = '\0';
224 savedir
= (char *) strdup (".");
225 saveprefix
= concat_dir_and_file (savedir
, "cooledit");
227 fd
= mc_mkstemps(&savename
, saveprefix
, NULL
);
232 * Close for now because mc_mkstemps use pure open system call
233 * to create temporary file and it needs to be reopened by
234 * VFS-aware mc_open().
238 savename
= g_strdup (filename
);
240 mc_chown (savename
, edit
->stat1
.st_uid
, edit
->stat1
.st_gid
);
241 mc_chmod (savename
, edit
->stat1
.st_mode
);
243 if ((fd
= mc_open (savename
, O_CREAT
| O_WRONLY
| O_TRUNC
| O_BINARY
,
244 edit
->stat1
.st_mode
)) == -1)
248 if ((p
= (char *) edit_get_write_filter (savename
, filename
))) {
252 file
= (FILE *) popen (p
, "w");
255 filelen
= edit_write_stream (edit
, file
);
259 if (pclose (file
) != 0) {
260 edit_error_dialog (_ ("Error"), catstrs (_ (" Error writing to pipe: "), p
, " ", 0));
266 edit_error_dialog (_ ("Error"), get_sys_error (catstrs (_ (" Failed trying to open pipe for writing: "), p
, " ", 0)));
274 filelen
= edit
->last_byte
;
275 while (buf
<= (edit
->curs1
>> S_EDIT_BUF_SIZE
) - 1) {
276 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
282 if (mc_write (fd
, (char *) edit
->buffers1
[buf
], edit
->curs1
& M_EDIT_BUF_SIZE
) != (edit
->curs1
& M_EDIT_BUF_SIZE
)) {
284 } else if (edit
->curs2
) {
286 buf
= (edit
->curs2
>> S_EDIT_BUF_SIZE
);
287 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
)) {
291 if (mc_write (fd
, (char *) edit
->buffers2
[buf
], EDIT_BUF_SIZE
) != EDIT_BUF_SIZE
) {
303 if (filelen
!= edit
->last_byte
)
305 if (this_save_mode
== 2)
306 if (mc_rename (filename
, catstrs (filename
, option_backup_ext
, 0)) == -1)
308 if (this_save_mode
> 0)
309 if (mc_rename (savename
, filename
) == -1)
321 I changed this from Oleg's original routine so
322 that option_backup_ext works with coolwidgets as well. This
323 does mean there is a memory leak - paul.
325 void menu_save_mode_cmd (void)
329 static char *str_result
;
330 static int save_mode_new
;
335 N_("Do backups -->")};
336 static QuickWidget widgets
[] =
338 {quick_button
, 18, DLG_X
, 7, DLG_Y
, N_("&Cancel"), 0,
339 B_CANCEL
, 0, 0, "c"},
340 {quick_button
, 6, DLG_X
, 7, DLG_Y
, N_("&OK"), 0,
342 {quick_input
, 23, DLG_X
, 5, DLG_Y
, 0, 9,
343 0, 0, &str_result
, "edit-backup-ext"},
344 {quick_label
, 22, DLG_X
, 4, DLG_Y
, N_("Extension:"), 0,
345 0, 0, 0, "savemext"},
346 {quick_radio
, 4, DLG_X
, 3, DLG_Y
, "", 3,
347 0, &save_mode_new
, str
, "t"},
349 static QuickDialog dialog
=
350 {DLG_X
, DLG_Y
, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
352 static int i18n_flag
= 0;
360 /* Ok/Cancel buttons */
361 l1
= strlen (_(widgets
[0].text
)) + strlen (_(widgets
[1].text
)) + 5;
362 maxlen
= max (maxlen
, l1
);
364 for (i
= 0; i
< 3; i
++ ) {
366 maxlen
= max (maxlen
, strlen (str
[i
]) + 7);
370 dlg_x
= maxlen
+ strlen (_(widgets
[3].text
)) + 5 + 1;
371 widgets
[2].hotkey_pos
= strlen (_(widgets
[3].text
)); /* input field length */
372 dlg_x
= min (COLS
, dlg_x
);
376 widgets
[1].relative_x
= i
;
377 widgets
[0].relative_x
= i
+ strlen (_(widgets
[1].text
)) + i
+ 4;
379 widgets
[2].relative_x
= widgets
[3].relative_x
= maxlen
+ 2;
381 for (i
= 0; i
< sizeof (widgets
)/sizeof (widgets
[0]); i
++)
382 widgets
[i
].x_divisions
= dlg_x
;
385 widgets
[2].text
= option_backup_ext
;
386 widgets
[4].value
= option_save_mode
;
387 if (quick_dialog (&dialog
) != B_ENTER
)
389 option_save_mode
= save_mode_new
;
390 option_backup_ext
= str_result
; /* this is a memory leak */
391 option_backup_ext_int
= 0;
392 str_result
[min (strlen (str_result
), sizeof (int))] = '\0';
393 memcpy ((char *) &option_backup_ext_int
, str_result
, strlen (option_backup_ext
));
396 void edit_split_filename (WEdit
* edit
, const char *f
)
399 free (edit
->filename
);
400 edit
->filename
= (char *) strdup (f
);
403 edit
->dir
= (char *) strdup ("");
406 /* Here we want to warn the users of overwriting an existing file,
407 but only if they have made a change to the filename */
408 /* returns 1 on success */
409 int edit_save_as_cmd (WEdit
* edit
)
411 /* This heads the 'Save As' dialog box */
413 int different_filename
= 0;
415 exp
= edit_get_save_file (edit
->dir
, edit
->filename
, _(" Save As "));
416 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
421 edit
->force
|= REDRAW_COMPLETELY
;
424 if (strcmp(catstrs (edit
->dir
, edit
->filename
, 0), exp
)) {
426 different_filename
= 1;
427 if ((file
= mc_open (exp
, O_RDONLY
| O_BINARY
)) != -1) { /* the file exists */
429 if (edit_query_dialog2 (_("Warning"),
430 _(" A file already exists with this name. "),
431 /* Push buttons to over-write the current file, or cancel the operation */
432 _("Overwrite"), _("Cancel"))) {
433 edit
->force
|= REDRAW_COMPLETELY
;
439 if (edit_save_file (edit
, exp
)) {
440 edit_split_filename (edit
, exp
);
443 edit
->delete_file
= 0;
444 if (different_filename
&& !edit
->explicit_syntax
)
445 edit_load_syntax (edit
, 0, 0);
446 edit
->force
|= REDRAW_COMPLETELY
;
450 edit_error_dialog (_(" Save As "), get_sys_error (_(" Error trying to save file. ")));
451 edit
->force
|= REDRAW_COMPLETELY
;
456 edit
->force
|= REDRAW_COMPLETELY
;
460 /* {{{ Macro stuff starts here */
463 raw_callback (struct Dlg_head
*h
, int key
, int Msg
)
471 return default_dlg_callback (h
, key
, Msg
);;
474 /* gets a raw key from the keyboard. Passing cancel = 1 draws
475 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
476 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
477 and Esc are cannot returned */
479 edit_raw_key_query (char *heading
, char *query
, int cancel
)
481 int w
= strlen (query
) + 7;
482 struct Dlg_head
*raw_dlg
=
483 create_dlg (0, 0, 7, w
, dialog_colors
, raw_callback
,
485 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
488 button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
,
489 _("Cancel"), 0, 0, 0));
490 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
, 0));
492 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0));
494 w
= raw_dlg
->ret_value
;
495 destroy_dlg (raw_dlg
);
497 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
505 /* creates a macro file if it doesn't exist */
506 static FILE *edit_open_macro_file (const char *r
)
510 filename
= catstrs (home_dir
, MACRO_FILE
, 0);
511 if ((file
= open (filename
, O_CREAT
| O_RDWR
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
)) == -1)
514 return fopen (filename
, r
);
517 #define MAX_MACROS 1024
518 static int saved_macro
[MAX_MACROS
+ 1];
519 static int saved_macros_loaded
= 0;
522 This is just to stop the macro file be loaded over and over for keys
523 that aren't defined to anything. On slow systems this could be annoying.
529 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++)
530 if (saved_macro
[i
] == k
)
535 /* returns 1 on error */
537 edit_delete_macro (WEdit
* edit
, int k
)
539 struct macro macro
[MAX_MACRO_LENGTH
];
543 if (saved_macros_loaded
)
544 if ((j
= macro_exists (k
)) < 0)
546 g
= fopen (catstrs (home_dir
, TEMP_FILE
, 0), "w");
548 /* This heads the delete macro error dialog box */
549 edit_error_dialog (_(" Delete macro "),
550 /* 'Open' = load temp file */
551 get_sys_error (_(" Error trying to open temp file ")));
554 f
= edit_open_macro_file ("r");
556 /* This heads the delete macro error dialog box */
557 edit_error_dialog (_(" Delete macro "),
558 /* 'Open' = load temp file */
559 get_sys_error (_(" Error trying to open macro file ")));
564 n
= fscanf (f
, ("key '%d 0': "), &s
);
568 while (fscanf (f
, "%hd %hd, ", ¯o
[n
].command
, ¯o
[n
].ch
))
572 fprintf (g
, ("key '%d 0': "), s
);
573 for (i
= 0; i
< n
; i
++)
574 fprintf (g
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
580 if (rename (catstrs (home_dir
, TEMP_FILE
, 0), catstrs (home_dir
, MACRO_FILE
, 0)) == -1) {
581 /* This heads the delete macro error dialog box */
582 edit_error_dialog (_(" Delete macro "),
583 get_sys_error (_(" Error trying to overwrite macro file ")));
586 if (saved_macros_loaded
)
587 memmove (saved_macro
+ j
, saved_macro
+ j
+ 1, sizeof (int) * (MAX_MACROS
- j
- 1));
591 /* returns 0 on error */
592 int edit_save_macro_cmd (WEdit
* edit
, struct macro macro
[], int n
)
597 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
598 /* This heads the 'Macro' dialog box */
599 s
= edit_raw_key_query (_(" Save macro "),
600 /* Input line for a single key press follows the ':' */
601 _(" Press the macro's new hotkey: "), 1);
602 edit
->force
|= REDRAW_COMPLETELY
;
604 if (edit_delete_macro (edit
, s
))
606 f
= edit_open_macro_file ("a+");
608 fprintf (f
, ("key '%d 0': "), s
);
609 for (i
= 0; i
< n
; i
++)
610 fprintf (f
, "%hd %hd, ", macro
[i
].command
, macro
[i
].ch
);
613 if (saved_macros_loaded
) {
614 for (i
= 0; i
< MAX_MACROS
&& saved_macro
[i
]; i
++);
619 /* This heads the 'Save Macro' dialog box */
620 edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
625 void edit_delete_macro_cmd (WEdit
* edit
)
629 command
= edit_raw_key_query (_ (" Delete macro "),
630 _ (" Press macro hotkey: "), 1);
635 edit_delete_macro (edit
, command
);
638 /* return 0 on error */
639 int edit_load_macro_cmd (WEdit
* edit
, struct macro macro
[], int *n
, int k
)
642 int s
, i
= 0, found
= 0;
644 if (saved_macros_loaded
)
645 if (macro_exists (k
) < 0)
648 if ((f
= edit_open_macro_file ("r"))) {
652 u
= fscanf (f
, ("key '%d 0': "), &s
);
655 if (!saved_macros_loaded
)
656 saved_macro
[i
++] = s
;
659 while (*n
< MAX_MACRO_LENGTH
&& 2 == fscanf (f
, "%hd %hd, ", ¯o
[*n
].command
, ¯o
[*n
].ch
))
662 while (2 == fscanf (f
, "%hd %hd, ", &dummy
.command
, &dummy
.ch
));
667 } while (!found
|| !saved_macros_loaded
);
668 if (!saved_macros_loaded
) {
670 saved_macros_loaded
= 1;
675 /* This heads the 'Load Macro' dialog box */
676 edit_error_dialog (_(" Load macro "),
677 get_sys_error (_(" Error trying to open macro file ")));
681 /* }}} Macro stuff starts here */
683 /* returns 1 on success */
684 int edit_save_confirm_cmd (WEdit
* edit
)
688 if (edit_confirm_save
) {
689 f
= catstrs (_(" Confirm save file? : "), edit
->filename
, " ", 0);
690 /* Buttons to 'Confirm save file' query */
691 if (edit_query_dialog2 (_(" Save file "), f
, _("Save"), _("Cancel")))
694 return edit_save_cmd (edit
);
698 /* returns 1 on success */
699 int edit_save_cmd (WEdit
* edit
)
701 if (!edit_save_file (edit
, catstrs (edit
->dir
, edit
->filename
, 0)))
702 return edit_save_as_cmd (edit
);
703 edit
->force
|= REDRAW_COMPLETELY
;
705 edit
->delete_file
= 0;
711 /* returns 1 on success */
712 int edit_new_cmd (WEdit
* edit
)
714 if (edit
->modified
) {
715 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
716 edit
->force
|= REDRAW_COMPLETELY
;
720 edit
->force
|= REDRAW_COMPLETELY
;
722 return edit_renew (edit
); /* if this gives an error, something has really screwed up */
725 /* returns 1 on error */
727 edit_load_file_from_filename (WEdit
* edit
, char *exp
)
729 if (!edit_reload (edit
, exp
, 0, "", 0))
731 edit_split_filename (edit
, exp
);
736 int edit_load_cmd (WEdit
* edit
)
740 if (edit
->modified
) {
741 if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
742 edit
->force
|= REDRAW_COMPLETELY
;
747 exp
= edit_get_load_file (edit
->dir
, edit
->filename
, _ (" Load "));
751 edit_load_file_from_filename (edit
, exp
);
754 edit
->force
|= REDRAW_COMPLETELY
;
759 if mark2 is -1 then marking is from mark1 to the cursor.
760 Otherwise its between the markers. This handles this.
761 Returns 1 if no text is marked.
763 int eval_marks (WEdit
* edit
, long *start_mark
, long *end_mark
)
765 if (edit
->mark1
!= edit
->mark2
) {
766 if (edit
->mark2
>= 0) {
767 *start_mark
= min (edit
->mark1
, edit
->mark2
);
768 *end_mark
= max (edit
->mark1
, edit
->mark2
);
770 *start_mark
= min (edit
->mark1
, edit
->curs1
);
771 *end_mark
= max (edit
->mark1
, edit
->curs1
);
772 edit
->column2
= edit
->curs_col
;
776 *start_mark
= *end_mark
= 0;
777 edit
->column2
= edit
->column1
= 0;
782 #define space_width 1
785 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_cursor_move (edit
, edit
->last_byte
- edit
->curs1
);
805 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
;
943 edit_delete_column_of_text (WEdit
* edit
)
945 long p
, q
, r
, m1
, m2
;
949 eval_marks (edit
, &m1
, &m2
);
950 n
= edit_move_forward (edit
, m1
, 0, m2
) + 1;
951 c
= edit_move_forward3 (edit
, edit_bol (edit
, m1
), 0, m1
);
952 d
= edit_move_forward3 (edit
, edit_bol (edit
, m2
), 0, m2
);
958 r
= edit_bol (edit
, edit
->curs1
);
959 p
= edit_move_forward3 (edit
, r
, b
, 0);
960 q
= edit_move_forward3 (edit
, r
, c
, 0);
965 edit_cursor_move (edit
, p
- edit
->curs1
);
966 while (q
> p
) { /* delete line between margins */
967 if (edit_get_byte (edit
, edit
->curs1
) != '\n')
971 if (n
) /* move to next line except on the last delete */
972 edit_cursor_move (edit
, edit_move_forward (edit
, edit
->curs1
, 1, 0) - edit
->curs1
);
976 /* if success return 0 */
978 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
991 (" Block is large, you may not be able to undo this action. "),
992 _("Continue"), _("Cancel"))) {
996 edit_push_markers (edit
);
997 edit_cursor_move (edit
, start_mark
- edit
->curs1
);
998 edit_scroll_screen_over_cursor (edit
);
1000 if (start_mark
< end_mark
) {
1001 if (column_highlighting
) {
1002 if (edit
->mark2
< 0)
1003 edit_mark_cmd (edit
, 0);
1004 edit_delete_column_of_text (edit
);
1006 while (count
< end_mark
) {
1012 edit_set_markers (edit
, 0, 0, 0, 0);
1013 edit
->force
|= REDRAW_PAGE
;
1017 /* returns 1 if canceelled by user */
1018 int edit_block_delete_cmd (WEdit
* edit
)
1020 long start_mark
, end_mark
;
1021 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
1022 edit_delete_line (edit
);
1025 return edit_block_delete (edit
);
1029 #define INPUT_INDEX 9
1030 #define SEARCH_DLG_WIDTH 58
1031 #define SEARCH_DLG_HEIGHT 10
1032 #define REPLACE_DLG_WIDTH 58
1033 #define REPLACE_DLG_HEIGHT 15
1034 #define CONFIRM_DLG_WIDTH 79
1035 #define CONFIRM_DLG_HEIGTH 6
1036 #define B_REPLACE_ALL B_USER+1
1037 #define B_REPLACE_ONE B_USER+2
1038 #define B_SKIP_REPLACE B_USER+3
1041 edit_replace_prompt (WEdit
* edit
, char *replace_text
, int xpos
, int ypos
)
1043 QuickWidget quick_widgets
[] =
1045 {quick_button
, 63, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Cancel"),
1046 0, B_CANCEL
, 0, 0, NULL
},
1047 {quick_button
, 50, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("O&ne"),
1048 0, B_REPLACE_ONE
, 0, 0, NULL
},
1049 {quick_button
, 37, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("A&ll"),
1050 0, B_REPLACE_ALL
, 0, 0, NULL
},
1051 {quick_button
, 21, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Skip"),
1052 0, B_SKIP_REPLACE
, 0, 0, NULL
},
1053 {quick_button
, 4, CONFIRM_DLG_WIDTH
, 3, CONFIRM_DLG_HEIGTH
, N_ ("&Replace"),
1054 0, B_ENTER
, 0, 0, NULL
},
1055 {quick_label
, 2, CONFIRM_DLG_WIDTH
, 2, CONFIRM_DLG_HEIGTH
, 0,
1060 char *msg
= _(" Replace with: ");
1062 quick_widgets
[5].text
= catstrs (msg
, replace_text
, 0);
1065 convert_to_display (quick_widgets
[5].text
+ strlen (msg
));
1067 quick_widgets
[5].text
= catstrs (_ (" Replace with: "), replace_text
, 0);
1068 #endif /* !HAVE_CHARSET */
1071 QuickDialog Quick_input
=
1072 {CONFIRM_DLG_WIDTH
, CONFIRM_DLG_HEIGTH
, 0, 0, N_ (" Confirm replace "),
1073 "[Input Line Keys]", 0 /*quick_widgets */ };
1075 Quick_input
.widgets
= quick_widgets
;
1077 Quick_input
.xpos
= xpos
;
1079 /* Sometimes menu can hide replaced text. I don't like it */
1081 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ CONFIRM_DLG_HEIGTH
- 1))
1082 ypos
-= CONFIRM_DLG_HEIGTH
;
1084 Quick_input
.ypos
= ypos
;
1085 return quick_dialog (&Quick_input
);
1090 edit_replace_dialog (WEdit
* edit
, char **search_text
, char **replace_text
, char **arg_order
)
1092 int treplace_scanf
= replace_scanf
;
1093 int treplace_regexp
= replace_regexp
;
1094 int treplace_all
= replace_all
;
1095 int treplace_prompt
= replace_prompt
;
1096 int treplace_backwards
= replace_backwards
;
1097 int treplace_whole
= replace_whole
;
1098 int treplace_case
= replace_case
;
1100 QuickWidget quick_widgets
[] =
1102 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1104 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1106 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1108 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("replace &All"), 0, 0,
1110 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("pr&Ompt on replace"), 0, 0,
1112 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 11, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1114 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 10, REPLACE_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1116 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1118 {quick_checkbox
, 4, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1120 {quick_input
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1122 {quick_label
, 2, REPLACE_DLG_WIDTH
, 6, REPLACE_DLG_HEIGHT
, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
1124 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1126 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"), 0, 0, 0,
1128 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, "", 52, 0, 0,
1130 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1134 quick_widgets
[2].result
= &treplace_scanf
;
1135 quick_widgets
[3].result
= &treplace_all
;
1136 quick_widgets
[4].result
= &treplace_prompt
;
1137 quick_widgets
[5].result
= &treplace_backwards
;
1138 quick_widgets
[6].result
= &treplace_regexp
;
1139 quick_widgets
[7].result
= &treplace_whole
;
1140 quick_widgets
[8].result
= &treplace_case
;
1141 quick_widgets
[9].str_result
= arg_order
;
1142 quick_widgets
[9].text
= *arg_order
;
1143 quick_widgets
[11].str_result
= replace_text
;
1144 quick_widgets
[11].text
= *replace_text
;
1145 quick_widgets
[13].str_result
= search_text
;
1146 quick_widgets
[13].text
= *search_text
;
1148 QuickDialog Quick_input
=
1149 {REPLACE_DLG_WIDTH
, REPLACE_DLG_HEIGHT
, -1, 0, N_(" Replace "),
1150 "[Input Line Keys]", 0 /*quick_widgets */ };
1152 Quick_input
.widgets
= quick_widgets
;
1154 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1155 replace_scanf
= treplace_scanf
;
1156 replace_backwards
= treplace_backwards
;
1157 replace_regexp
= treplace_regexp
;
1158 replace_all
= treplace_all
;
1159 replace_prompt
= treplace_prompt
;
1160 replace_whole
= treplace_whole
;
1161 replace_case
= treplace_case
;
1165 *replace_text
= NULL
;
1166 *search_text
= NULL
;
1174 edit_search_dialog (WEdit
* edit
, char **search_text
)
1176 int treplace_scanf
= replace_scanf
;
1177 int treplace_regexp
= replace_regexp
;
1178 int treplace_whole
= replace_whole
;
1179 int treplace_case
= replace_case
;
1180 int treplace_backwards
= replace_backwards
;
1182 QuickWidget quick_widgets
[] =
1184 {quick_button
, 6, 10, 7, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
1186 {quick_button
, 2, 10, 7, SEARCH_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
1188 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("scanf &Expression"), 0, 0,
1190 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
1192 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Regular expression"), 0, 0,
1194 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("&Whole words only"), 0, 0,
1196 {quick_checkbox
, 4, SEARCH_DLG_WIDTH
, 4, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
1198 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, "", 52, 0, 0,
1200 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0, 0,
1204 quick_widgets
[2].result
= &treplace_scanf
;
1205 quick_widgets
[3].result
= &treplace_backwards
;
1206 quick_widgets
[4].result
= &treplace_regexp
;
1207 quick_widgets
[5].result
= &treplace_whole
;
1208 quick_widgets
[6].result
= &treplace_case
;
1209 quick_widgets
[7].str_result
= search_text
;
1210 quick_widgets
[7].text
= *search_text
;
1213 QuickDialog Quick_input
=
1214 {SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_("Search"),
1215 "[Input Line Keys]", 0 /*quick_widgets */ };
1217 Quick_input
.widgets
= quick_widgets
;
1219 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
1220 replace_scanf
= treplace_scanf
;
1221 replace_backwards
= treplace_backwards
;
1222 replace_regexp
= treplace_regexp
;
1223 replace_whole
= treplace_whole
;
1224 replace_case
= treplace_case
;
1226 *search_text
= NULL
;
1232 static long sargs
[NUM_REPL_ARGS
][256 / sizeof (long)];
1234 #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
1235 sargs[4], sargs[5], sargs[6], sargs[7], \
1236 sargs[8], sargs[9], sargs[10], sargs[11], \
1237 sargs[12], sargs[13], sargs[14], sargs[15]
1239 #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
1240 sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
1241 sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
1242 sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
1245 /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
1246 /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
1248 string_regexp_search (char *pattern
, char *string
, int len
, int match_type
, int match_bol
, int icase
, int *found_len
, void *d
)
1251 static char *old_pattern
= NULL
;
1252 static int old_type
, old_icase
;
1254 static regmatch_t s
[1];
1256 pmatch
= (regmatch_t
*) d
;
1260 if (!old_pattern
|| strcmp (old_pattern
, pattern
) || old_type
!= match_type
|| old_icase
!= icase
) {
1266 if (regcomp (&r
, pattern
, REG_EXTENDED
| (icase
? REG_ICASE
: 0))) {
1270 old_pattern
= (char *) strdup (pattern
);
1271 old_type
= match_type
;
1274 if (regexec (&r
, string
, d
? NUM_REPL_ARGS
: 1, pmatch
, ((match_bol
|| match_type
!= match_normal
) ? 0 : REG_NOTBOL
)) != 0) {
1278 *found_len
= pmatch
[0].rm_eo
- pmatch
[0].rm_so
;
1279 return (pmatch
[0].rm_so
);
1282 /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
1283 (and the above) routines to work properly - paul */
1286 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
)
1289 long l
= strlen ((char *) exp
), f
= 0;
1292 for (p
= 0; p
< l
; p
++) /* count conversions... */
1294 if (exp
[++p
] != '%') /* ...except for "%%" */
1297 if (replace_scanf
|| replace_regexp
) {
1300 unsigned char mbuf
[MAX_REPL_LEN
* 2 + 3];
1302 replace_scanf
= (!replace_regexp
); /* can't have both */
1306 if (replace_scanf
) {
1307 unsigned char e
[MAX_REPL_LEN
];
1308 if (n
>= NUM_REPL_ARGS
)
1312 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++)
1313 buf
[p
- start
] = (*get_byte
) (data
, p
);
1315 for (p
= 0; exp
[p
] != 0; p
++)
1316 exp
[p
] = my_lower_case (exp
[p
]);
1317 for (p
= start
; p
< last_byte
&& p
< start
+ MAX_REPL_LEN
; p
++) {
1318 c
= (*get_byte
) (data
, p
);
1319 buf
[p
- start
] = my_lower_case (c
);
1323 buf
[(q
= p
- start
)] = 0;
1324 strcpy ((char *) e
, (char *) exp
);
1325 strcat ((char *) e
, "%n");
1329 *((int *) sargs
[n
]) = 0; /* --> here was the problem - now fixed: good */
1330 if (n
== sscanf ((char *) buf
, (char *) exp
, SCANF_ARGS
)) {
1331 if (*((int *) sargs
[n
])) {
1332 *len
= *((int *) sargs
[n
]);
1338 if (q
+ start
< last_byte
) {
1340 buf
[q
] = (*get_byte
) (data
, q
+ start
);
1342 c
= (*get_byte
) (data
, q
+ start
);
1343 buf
[q
] = my_lower_case (c
);
1349 buf
++; /* move the window along */
1350 if (buf
== mbuf
+ MAX_REPL_LEN
) { /* the window is about to go past the end of array, so... */
1351 memmove (mbuf
, buf
, strlen ((char *) buf
) + 1); /* reset it */
1356 } else { /* regexp matching */
1358 int found_start
, match_bol
, move_win
= 0;
1360 while (start
+ offset
< last_byte
) {
1361 match_bol
= (offset
== 0 || (*get_byte
) (data
, start
+ offset
- 1) == '\n');
1366 for (; p
< last_byte
&& q
< MAX_REPL_LEN
; p
++, q
++) {
1367 mbuf
[q
] = (*get_byte
) (data
, p
);
1368 if (mbuf
[q
] == '\n')
1377 found_start
= string_regexp_search ((char *) exp
, (char *) buf
, q
, match_normal
, match_bol
, !replace_case
, len
, d
);
1379 if (found_start
<= -2) { /* regcomp/regexec error */
1383 else if (found_start
== -1) /* not found: try next line */
1385 else if (*len
== 0) { /* null pattern: try again at next character */
1392 return (start
+ offset
- q
+ found_start
);
1397 if (buf
[q
- 1] != '\n') { /* incomplete line: try to recover */
1398 buf
= mbuf
+ MAX_REPL_LEN
/ 2;
1399 q
= strlen ((char *) buf
);
1400 memmove (mbuf
, buf
, q
);
1409 *len
= strlen ((char *) exp
);
1411 for (p
= start
; p
<= last_byte
- l
; p
++) {
1412 if ((*get_byte
) (data
, p
) == (unsigned char)exp
[0]) { /* check if first char matches */
1413 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1414 if ((*get_byte
) (data
, q
+ p
) != (unsigned char)exp
[q
])
1423 for (p
= 0; exp
[p
] != 0; p
++)
1424 exp
[p
] = my_lower_case (exp
[p
]);
1426 for (p
= start
; p
<= last_byte
- l
; p
++) {
1427 if (my_lower_case ((*get_byte
) (data
, p
)) == (unsigned char)exp
[0]) {
1428 for (f
= 0, q
= 0; q
< l
&& f
< 1; q
++)
1429 if (my_lower_case ((*get_byte
) (data
, q
+ p
)) != (unsigned char)exp
[q
])
1444 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
)
1445 { /*front end to find_string to check for
1450 while ((p
= edit_find_string (p
, exp
, len
, last_byte
, get_byte
, data
, once_only
, d
)) >= 0) {
1451 if (replace_whole
) {
1452 /*If the bordering chars are not in option_whole_chars_search then word is whole */
1453 if (!strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
- 1))
1454 && !strcasechr (option_whole_chars_search
, (*get_byte
) (data
, p
+ *len
)))
1462 p
++; /*not a whole word so continue search. */
1468 edit_find (long search_start
, unsigned char *exp
, int *len
, long last_byte
, int (*get_byte
) (void *, long), void *data
, void *d
)
1471 if (replace_backwards
) {
1472 while (search_start
>= 0) {
1473 p
= edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 1, d
);
1474 if (p
== search_start
)
1479 return edit_find_forwards (search_start
, exp
, len
, last_byte
, get_byte
, data
, 0, d
);
1484 #define is_digit(x) ((x) >= '0' && (x) <= '9')
1486 #define snprintf(v) { \
1491 sprintf(s,q1,v,&n); \
1495 /* this function uses the sprintf command to do a vprintf */
1496 /* it takes pointers to arguments instead of the arguments themselves */
1497 static int sprintf_p (char *str
, const char *fmt
,...)
1498 __attribute__ ((format (printf
, 2, 3)));
1500 static int sprintf_p (char *str
, const char *fmt
,...)
1504 char *q
, *p
, *s
= str
;
1509 p
= q
= (char *) fmt
;
1511 while ((p
= strchr (p
, '%'))) {
1513 strncpy (s
, q
, n
); /* copy stuff between format specifiers */
1541 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace field width with a number */
1544 while (is_digit (*p
))
1551 strcpy (p1
, MY_itoa (*va_arg (ap
, int *))); /* replace precision with a number */
1554 while (is_digit (*p
))
1557 /* flags done, now get argument */
1559 snprintf (va_arg (ap
, char *));
1560 } else if (*p
== 'h') {
1561 if (strchr ("diouxX", *p
))
1562 snprintf (*va_arg (ap
, short *));
1563 } else if (*p
== 'l') {
1565 if (strchr ("diouxX", *p
))
1566 snprintf (*va_arg (ap
, long *));
1567 } else if (strchr ("cdiouxX", *p
)) {
1568 snprintf (*va_arg (ap
, int *));
1569 } else if (*p
== 'L') {
1571 if (strchr ("EefgG", *p
))
1572 snprintf (*va_arg (ap
, double *)); /* should be long double */
1573 } else if (strchr ("EefgG", *p
)) {
1574 snprintf (*va_arg (ap
, double *));
1575 } else if (strchr ("DOU", *p
)) {
1576 snprintf (*va_arg (ap
, long *));
1577 } else if (*p
== 'p') {
1578 snprintf (*va_arg (ap
, void **));
1583 sprintf (s
, q
); /* print trailing leftover */
1584 return s
- str
+ strlen (s
);
1587 static void regexp_error (WEdit
*edit
)
1589 /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
1590 edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with to many conversions "));
1593 /* call with edit = 0 before shutdown to close memory leaks */
1595 edit_replace_cmd (WEdit
*edit
, int again
)
1597 static regmatch_t pmatch
[NUM_REPL_ARGS
];
1598 static char *old1
= NULL
;
1599 static char *old2
= NULL
;
1600 static char *old3
= NULL
;
1605 int replace_continue
;
1606 int treplace_prompt
= 0;
1608 long times_replaced
= 0, last_search
;
1609 int argord
[NUM_REPL_ARGS
];
1626 last_search
= edit
->last_byte
;
1628 edit
->force
|= REDRAW_COMPLETELY
;
1630 exp1
= old1
? old1
: exp1
;
1631 exp2
= old2
? old2
: exp2
;
1632 exp3
= old3
? old3
: exp3
;
1637 exp1
= g_strdup (old1
);
1638 exp2
= g_strdup (old2
);
1639 exp3
= g_strdup (old3
);
1641 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1643 convert_to_display (exp1
);
1644 convert_to_display (exp2
);
1646 edit_replace_dialog (edit
, &exp1
, &exp2
, &exp3
);
1648 convert_from_input (exp1
);
1649 convert_from_input (exp2
);
1651 treplace_prompt
= replace_prompt
;
1654 if (!exp1
|| !*exp1
) {
1655 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
1690 && replace_backwards
)
1691 edit
->search_start
--;
1693 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1
1694 && !replace_backwards
)
1695 edit
->search_start
++;
1701 edit_find (edit
->search_start
, (unsigned char *) exp1
, &len
,
1702 last_search
, (int (*)(void *, long)) edit_get_byte
,
1703 (void *) edit
, pmatch
);
1704 if (new_start
== -3) {
1705 regexp_error (edit
);
1708 edit
->search_start
= new_start
;
1709 /*returns negative on not found or error in pattern */
1711 if (edit
->search_start
>= 0) {
1712 edit
->found_start
= edit
->search_start
;
1713 i
= edit
->found_len
= len
;
1715 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1716 edit_scroll_screen_over_cursor (edit
);
1720 if (treplace_prompt
) {
1722 l
= edit
->curs_row
- edit
->num_widget_lines
/ 3;
1724 edit_scroll_downward (edit
, l
);
1726 edit_scroll_upward (edit
, -l
);
1728 edit_scroll_screen_over_cursor (edit
);
1729 edit
->force
|= REDRAW_PAGE
;
1730 edit_render_keypress (edit
);
1732 /*so that undo stops at each query */
1733 edit_push_key_press (edit
);
1735 switch (edit_replace_prompt (edit
, exp2
, /* and prompt 2/3 down */
1736 (edit
->num_widget_columns
-
1737 CONFIRM_DLG_WIDTH
) / 2,
1738 edit
->num_widget_lines
* 2 /
1742 case B_SKIP_REPLACE
:
1746 treplace_prompt
= 0;
1747 replace_continue
= 1;
1750 replace_continue
= 0;
1754 replace_continue
= 0;
1758 if (replace_yes
) { /* delete then insert new */
1759 if (replace_scanf
|| replace_regexp
) {
1760 char repl_str
[MAX_REPL_LEN
+ 2];
1762 /* we need to fill in sargs just like with scanf */
1763 if (replace_regexp
) {
1766 k
< NUM_REPL_ARGS
&& pmatch
[k
].rm_eo
>= 0;
1769 t
= (unsigned char *) &sargs
[k
- 1][0];
1771 j
< pmatch
[k
].rm_eo
- pmatch
[k
].rm_so
1772 && j
< 255; j
++, t
++)
1773 *t
= (unsigned char) edit_get_byte (edit
,
1786 for (; k
<= NUM_REPL_ARGS
; k
++)
1787 sargs
[k
- 1][0] = 0;
1789 if (sprintf_p (repl_str
, exp2
, PRINTF_ARGS
) >= 0) {
1793 while (repl_str
[++i
])
1794 edit_insert (edit
, repl_str
[i
]);
1796 edit_error_dialog (_(" Replace "),
1798 (" Error in replacement format string. "));
1799 replace_continue
= 0;
1806 edit_insert (edit
, exp2
[i
]);
1808 edit
->found_len
= i
;
1810 /* so that we don't find the same string again */
1811 if (replace_backwards
) {
1812 last_search
= edit
->search_start
;
1813 edit
->search_start
--;
1815 edit
->search_start
+= i
;
1816 last_search
= edit
->last_byte
;
1818 edit_scroll_screen_over_cursor (edit
);
1820 char *msg
= _(" Replace ");
1821 /* try and find from right here for next search */
1822 edit
->search_start
= edit
->curs1
;
1823 edit_update_curs_col (edit
);
1825 edit
->force
|= REDRAW_PAGE
;
1826 edit_render_keypress (edit
);
1827 if (times_replaced
) {
1828 message (0, msg
, _(" %ld replacements made. "),
1831 edit_message_dialog (msg
, _(" Search string not found "));
1832 replace_continue
= 0;
1834 } while (replace_continue
);
1839 edit
->force
= REDRAW_COMPLETELY
;
1840 edit_scroll_screen_over_cursor (edit
);
1846 void edit_search_cmd (WEdit
* edit
, int again
)
1848 static char *old
= NULL
;
1858 exp
= old
? old
: exp
;
1859 if (again
) { /*ctrl-hotkey for search again. */
1862 exp
= g_strdup (old
);
1867 convert_to_display (exp
);
1868 #endif /* HAVE_CHARSET */
1870 edit_search_dialog (edit
, &exp
);
1874 convert_from_input (exp
);
1875 #endif /* HAVE_CHARSET */
1877 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1885 old
= g_strdup (exp
);
1887 if (search_create_bookmark
) {
1888 int found
= 0, books
= 0;
1889 int l
= 0, l_last
= -1;
1892 p
= edit_find (q
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1893 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1897 l
+= edit_count_lines (edit
, q
, p
);
1899 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
1906 /* in response to number of bookmarks added because of string being found %d times */
1907 message (0, _("Search"), _(" %d finds made, %d bookmarks added "), found
, books
);
1909 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
1913 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
+ 1 && replace_backwards
)
1914 edit
->search_start
--;
1916 if (edit
->found_len
&& edit
->search_start
== edit
->found_start
- 1 && !replace_backwards
)
1917 edit
->search_start
++;
1919 edit
->search_start
= edit_find (edit
->search_start
, (unsigned char *) exp
, &len
, edit
->last_byte
,
1920 (int (*)(void *, long)) edit_get_byte
, (void *) edit
, 0);
1922 if (edit
->search_start
>= 0) {
1923 edit
->found_start
= edit
->search_start
;
1924 edit
->found_len
= len
;
1926 edit_cursor_move (edit
, edit
->search_start
- edit
->curs1
);
1927 edit_scroll_screen_over_cursor (edit
);
1928 if (replace_backwards
)
1929 edit
->search_start
--;
1931 edit
->search_start
++;
1932 } else if (edit
->search_start
== -3) {
1933 edit
->search_start
= edit
->curs1
;
1934 regexp_error (edit
);
1936 edit
->search_start
= edit
->curs1
;
1937 edit_error_dialog (_ ("Search"), _ (" Search string not found "));
1943 edit
->force
|= REDRAW_COMPLETELY
;
1944 edit_scroll_screen_over_cursor (edit
);
1948 /* Real edit only */
1949 void edit_quit_cmd (WEdit
* edit
)
1951 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
1953 edit
->force
|= REDRAW_COMPLETELY
;
1954 if (edit
->modified
) {
1955 switch (edit_query_dialog3 (_ ("Quit"), _ (" File was modified, Save with exit? "), _ ("Cancel quit"), _ ("&Yes"), _ ("&No"))) {
1957 edit_push_markers (edit
);
1958 edit_set_markers (edit
, 0, 0, 0, 0);
1959 if (!edit_save_cmd (edit
))
1963 if (edit
->delete_file
)
1964 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1971 else if (edit
->delete_file
)
1972 unlink (catstrs (edit
->dir
, edit
->filename
, 0));
1973 dlg_stop (edit
->widget
.parent
);
1976 #define TEMP_BUF_LEN 1024
1978 /* returns a null terminated length of text. Result must be free'd */
1979 unsigned char *edit_get_block (WEdit
* edit
, long start
, long finish
, int *l
)
1981 unsigned char *s
, *r
;
1982 r
= s
= malloc (finish
- start
+ 1);
1983 if (column_highlighting
) {
1985 while (start
< finish
) { /* copy from buffer, excluding chars that are out of the column 'margins' */
1987 x
= edit_move_forward3 (edit
, edit_bol (edit
, start
), 0, start
);
1988 c
= edit_get_byte (edit
, start
);
1989 if ((x
>= edit
->column1
&& x
< edit
->column2
)
1990 || (x
>= edit
->column2
&& x
< edit
->column1
) || c
== '\n') {
1997 *l
= finish
- start
;
1998 while (start
< finish
)
1999 *s
++ = edit_get_byte (edit
, start
++);
2005 /* save block, returns 1 on success */
2007 edit_save_block (WEdit
* edit
, const char *filename
, long start
,
2013 mc_open (filename
, O_CREAT
| O_WRONLY
| O_TRUNC
,
2014 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
| O_BINARY
)) == -1)
2017 if (column_highlighting
) {
2018 unsigned char *block
, *p
;
2020 p
= block
= edit_get_block (edit
, start
, finish
, &len
);
2022 r
= mc_write (file
, p
, len
);
2032 len
= finish
- start
;
2033 buf
= malloc (TEMP_BUF_LEN
);
2034 while (start
!= finish
) {
2035 end
= min (finish
, start
+ TEMP_BUF_LEN
);
2036 for (; i
< end
; i
++)
2037 buf
[i
- start
] = edit_get_byte (edit
, i
);
2038 len
-= mc_write (file
, (char *) buf
, end
- start
);
2049 /* copies a block to clipboard file */
2050 static int edit_save_block_to_clip_file (WEdit
* edit
, long start
, long finish
)
2052 return edit_save_block (edit
, catstrs (home_dir
, CLIP_FILE
, 0), start
, finish
);
2056 void edit_paste_from_history (WEdit
*edit
)
2060 int edit_copy_to_X_buf_cmd (WEdit
* edit
)
2062 long start_mark
, end_mark
;
2063 if (eval_marks (edit
, &start_mark
, &end_mark
))
2065 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2066 edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
2069 edit_mark_cmd (edit
, 1);
2073 int edit_cut_to_X_buf_cmd (WEdit
* edit
)
2075 long start_mark
, end_mark
;
2076 if (eval_marks (edit
, &start_mark
, &end_mark
))
2078 if (!edit_save_block_to_clip_file (edit
, start_mark
, end_mark
)) {
2079 edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
2082 edit_block_delete_cmd (edit
);
2083 edit_mark_cmd (edit
, 1);
2087 void edit_paste_from_X_buf_cmd (WEdit
* edit
)
2089 edit_insert_file (edit
, catstrs (home_dir
, CLIP_FILE
, 0));
2093 void edit_goto_cmd (WEdit
*edit
)
2098 sprintf (s
, "%d", l
);
2099 f
= input_dialog (_(" Goto line "), _(" Enter line: "), l
? s
: "");
2103 edit_move_display (edit
, l
- edit
->num_widget_lines
/ 2 - 1);
2104 edit_move_to_line (edit
, l
- 1);
2105 edit
->force
|= REDRAW_COMPLETELY
;
2111 /*returns 1 on success */
2112 int edit_save_block_cmd (WEdit
* edit
)
2114 long start_mark
, end_mark
;
2116 if (eval_marks (edit
, &start_mark
, &end_mark
))
2118 exp
= edit_get_save_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0), _ (" Save Block "));
2119 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2125 if (edit_save_block (edit
, exp
, start_mark
, end_mark
)) {
2127 edit
->force
|= REDRAW_COMPLETELY
;
2131 edit_error_dialog (_ (" Save Block "), get_sys_error (_ (" Error trying to save file. ")));
2135 edit
->force
|= REDRAW_COMPLETELY
;
2140 /* returns 1 on success */
2142 edit_insert_file_cmd (WEdit
*edit
)
2145 edit_get_load_file (edit
->dir
, catstrs (home_dir
, CLIP_FILE
, 0),
2146 _(" Insert File "));
2147 edit_push_action (edit
, KEY_PRESS
+ edit
->start_display
);
2153 if (edit_insert_file (edit
, exp
)) {
2155 edit
->force
|= REDRAW_COMPLETELY
;
2159 edit_error_dialog (_(" Insert File "),
2161 (" Error trying to insert file. ")));
2165 edit
->force
|= REDRAW_COMPLETELY
;
2169 /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
2170 int edit_sort_cmd (WEdit
* edit
)
2172 static char *old
= 0;
2174 long start_mark
, end_mark
;
2177 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2178 edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
2181 edit_save_block (edit
, catstrs (home_dir
, BLOCK_FILE
, 0), start_mark
, end_mark
);
2183 exp
= old
? old
: "";
2185 exp
= input_dialog (_(" Run Sort "),
2186 _(" Enter sort options (see manpage) separated by whitespace: "), exp
);
2194 e
= system (catstrs (" sort ", exp
, " ", home_dir
, BLOCK_FILE
, " > ", home_dir
, TEMP_FILE
, 0));
2196 if (e
== -1 || e
== 127) {
2197 edit_error_dialog (_(" Sort "),
2198 get_sys_error (_(" Error trying to execute sort command ")));
2201 sprintf (q
, "%d ", e
);
2202 edit_error_dialog (_(" Sort "),
2203 catstrs (_(" Sort returned non-zero: "), q
, 0));
2208 edit
->force
|= REDRAW_COMPLETELY
;
2210 if (edit_block_delete_cmd (edit
))
2212 edit_insert_file (edit
, catstrs (home_dir
, TEMP_FILE
, 0));
2216 /* if block is 1, a block must be highlighted and the shell command
2217 processes it. If block is 0 the shell command is a straight system
2218 command, that just produces some output which is to be inserted */
2220 edit_block_process_cmd (WEdit
* edit
, const char *shell_cmd
, int block
)
2222 long start_mark
, end_mark
;
2224 FILE *script_home
= NULL
;
2225 FILE *script_src
= NULL
;
2226 FILE *block_file
= NULL
;
2231 o
= catstrs (mc_home
, shell_cmd
, 0); /* original source script */
2232 h
= catstrs (home_dir
, EDIT_DIR
, shell_cmd
, 0); /* home script */
2233 b
= catstrs (home_dir
, BLOCK_FILE
, 0); /* block file */
2235 if (!(script_home
= fopen (h
, "r"))) {
2236 if (!(script_home
= fopen (h
, "w"))) {
2237 edit_error_dialog ("", get_sys_error (catstrs
2239 ("Error creating script:"),
2243 if (!(script_src
= fopen (o
, "r"))) {
2244 fclose (script_home
);
2246 edit_error_dialog ("", get_sys_error (catstrs
2247 (_("Error reading script:"),
2251 while (fgets (buf
, sizeof (buf
), script_src
))
2252 fputs (buf
, script_home
);
2253 if (fclose (script_home
)) {
2254 edit_error_dialog ("", get_sys_error (catstrs
2256 ("Error closing script:"),
2261 edit_error_dialog ("", get_sys_error (catstrs
2262 (_("Script created:"), h
,
2268 if (block
) { /* for marked block run indent formatter */
2269 if (eval_marks (edit
, &start_mark
, &end_mark
)) {
2270 edit_error_dialog (_("Process block"),
2272 (" You must first highlight a block of text. "));
2275 edit_save_block (edit
, b
, start_mark
, end_mark
);
2279 * Initial space is to avoid polluting bash history.
2281 * $1 - name of the edited file (to check its extention etc).
2282 * $2 - file containing the current block.
2283 * $3 - file where error messages should be put
2284 * (for compatibility with old scripts).
2286 system (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2287 edit
->filename
, " ", home_dir
, BLOCK_FILE
,
2288 " /dev/null", NULL
));
2292 * No block selected, just execute the command for the file.
2294 * $1 - name of the edited file.
2296 system (catstrs (" ", home_dir
, EDIT_DIR
, shell_cmd
, " ",
2297 edit
->filename
, NULL
));
2300 close_error_pipe (0, 0);
2302 edit_refresh_cmd (edit
);
2303 edit
->force
|= REDRAW_COMPLETELY
;
2305 /* insert result block */
2307 if (edit_block_delete_cmd (edit
))
2309 edit_insert_file (edit
, b
);
2310 if ((block_file
= fopen (b
, "w")))
2311 fclose (block_file
);
2318 /* prints at the cursor */
2319 /* returns the number of chars printed */
2320 int edit_print_string (WEdit
* e
, const char *s
)
2324 edit_execute_cmd (e
, -1, (unsigned char) s
[i
++]);
2325 e
->force
|= REDRAW_COMPLETELY
;
2326 edit_update_screen (e
);
2330 int edit_printf (WEdit
* e
, const char *fmt
, ...)
2336 g_vsnprintf (s
, sizeof (s
), fmt
, pa
);
2337 i
= edit_print_string (e
, s
);
2342 /* FIXME: does this function break NT_OS2 ? */
2344 static void pipe_mail (WEdit
*edit
, char *to
, char *subject
, char *cc
)
2349 s
= g_strdup_printf ("mail -s \"%s\" -c \"%s\" \"%s\"", subject
, cc
, to
);
2358 for (i
= 0; i
< edit
->last_byte
; i
++)
2359 fputc (edit_get_byte (edit
, i
), p
);
2364 #define MAIL_DLG_HEIGHT 12
2366 void edit_mail_dialog (WEdit
* edit
)
2369 char *tmail_subject
;
2372 static char *mail_cc_last
= 0;
2373 static char *mail_subject_last
= 0;
2374 static char *mail_to_last
= 0;
2376 QuickDialog Quick_input
=
2377 {50, MAIL_DLG_HEIGHT
, -1, 0, N_(" Mail "),
2378 "[Input Line Keys]", 0};
2380 QuickWidget quick_widgets
[] =
2382 {quick_button
, 6, 10, 9, MAIL_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
2384 {quick_button
, 2, 10, 9, MAIL_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
2386 {quick_input
, 3, 50, 8, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2387 0, "mail-dlg-input"},
2388 {quick_label
, 2, 50, 7, MAIL_DLG_HEIGHT
, N_(" Copies to"), 0, 0, 0,
2390 {quick_input
, 3, 50, 6, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2391 0, "mail-dlg-input-2"},
2392 {quick_label
, 2, 50, 5, MAIL_DLG_HEIGHT
, N_(" Subject"), 0, 0, 0,
2394 {quick_input
, 3, 50, 4, MAIL_DLG_HEIGHT
, "", 44, 0, 0,
2395 0, "mail-dlg-input-3"},
2396 {quick_label
, 2, 50, 3, MAIL_DLG_HEIGHT
, N_(" To"), 0, 0, 0,
2398 {quick_label
, 2, 50, 2, MAIL_DLG_HEIGHT
, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
2402 quick_widgets
[2].str_result
= &tmail_cc
;
2403 quick_widgets
[2].text
= mail_cc_last
? mail_cc_last
: "";
2404 quick_widgets
[4].str_result
= &tmail_subject
;
2405 quick_widgets
[4].text
= mail_subject_last
? mail_subject_last
: "";
2406 quick_widgets
[6].str_result
= &tmail_to
;
2407 quick_widgets
[6].text
= mail_to_last
? mail_to_last
: "";
2409 Quick_input
.widgets
= quick_widgets
;
2411 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
2413 g_free (mail_cc_last
);
2414 if (mail_subject_last
)
2415 g_free (mail_subject_last
);
2417 g_free (mail_to_last
);
2418 mail_cc_last
= *(quick_widgets
[2].str_result
);
2419 mail_subject_last
= *(quick_widgets
[4].str_result
);
2420 mail_to_last
= *(quick_widgets
[6].str_result
);
2421 pipe_mail (edit
, mail_to_last
, mail_subject_last
, mail_cc_last
);
2426 /*******************/
2427 /* Word Completion */
2428 /*******************/
2431 /* find first character of current word */
2432 static int edit_find_word_start (WEdit
*edit
, long *word_start
, int *word_len
)
2436 /* return if at begin of file */
2437 if (edit
->curs1
<= 0)
2440 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- 1);
2441 /* return if not at end or in word */
2442 if (isspace (c
) || !(isalnum (c
) || c
== '_'))
2445 /* search start of word to be completed */
2447 /* return if at begin of file */
2448 if (edit
->curs1
- i
< 0)
2452 c
= (unsigned char) edit_get_byte (edit
, edit
->curs1
- i
);
2454 if (!(isalnum (c
) || c
== '_')) {
2455 /* return if word starts with digit */
2459 *word_start
= edit
->curs1
- (i
- 1); /* start found */
2469 /* (re)set search parameters to the given values */
2470 static void edit_set_search_parameters (int rs
, int rb
, int rr
, int rw
, int rc
)
2473 replace_backwards
= rb
;
2474 replace_regexp
= rr
;
2480 #define MAX_WORD_COMPLETIONS 100 /* in listbox */
2482 /* collect the possible completions */
2483 static int edit_collect_completions (WEdit
*edit
, long start
,
2484 int word_len
, char *match_expr
, struct selection
*compl, int *num
)
2486 int len
, max_len
= 0, i
, skip
;
2489 /* collect max MAX_WORD_COMPLETIONS completions */
2490 while (*num
< MAX_WORD_COMPLETIONS
) {
2491 /* get next match */
2492 start
= edit_find (start
- 1, (unsigned char *) match_expr
, &len
,
2493 edit
->last_byte
, (int (*)(void *, long)) edit_get_byte
,
2500 /* add matched completion if not yet added */
2501 bufpos
= &edit
->buffers1
[start
>> S_EDIT_BUF_SIZE
][start
& M_EDIT_BUF_SIZE
];
2503 for (i
= 0; i
< *num
; i
++) {
2504 if (strncmp (&compl[i
].text
[word_len
], &bufpos
[word_len
],
2505 max (len
, compl[i
].len
) - word_len
) == 0) {
2507 break; /* skip it, already added */
2513 compl[*num
].text
= CMalloc (len
+ 1);
2514 compl[*num
].len
= len
;
2515 for (i
= 0; i
< len
; i
++)
2516 compl[*num
].text
[i
] = *(bufpos
+ i
);
2517 compl[*num
].text
[i
] = '\0';
2520 /* note the maximal length needed for the completion dialog */
2528 static int compllist_callback (void *data
)
2534 /* let the user select its preferred completion */
2536 edit_completion_dialog (WEdit
*edit
, int max_len
, int word_len
,
2537 struct selection
*compl, int num_compl
)
2539 int start_x
, start_y
, offset
, i
;
2541 Dlg_head
*compl_dlg
;
2542 WListbox
*compl_list
;
2543 unsigned int compl_dlg_h
; /* completion dialog height */
2544 unsigned int compl_dlg_w
; /* completion dialog width */
2546 /* calculate the dialog metrics */
2547 compl_dlg_h
= num_compl
+ 2;
2548 compl_dlg_w
= max_len
+ 4;
2549 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2);
2550 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
2554 if (compl_dlg_w
> COLS
)
2556 if (compl_dlg_h
> LINES
- 2)
2557 compl_dlg_h
= LINES
- 2;
2559 offset
= start_x
+ compl_dlg_w
- COLS
;
2562 offset
= start_y
+ compl_dlg_h
- LINES
;
2564 start_y
-= (offset
+ 1);
2566 /* create the dialog */
2567 compl_dlg
= create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
2568 dialog_colors
, NULL
, "[Completion]", NULL
,
2571 /* create the listbox */
2572 compl_list
= listbox_new (1, 1, compl_dlg_w
- 2, compl_dlg_h
- 2, 0,
2573 compllist_callback
, NULL
);
2575 /* add the dialog */
2576 add_widget (compl_dlg
, compl_list
);
2578 /* fill the listbox with the completions */
2579 for (i
= 0; i
< num_compl
; i
++)
2580 listbox_add_item (compl_list
, 0, 0, compl[i
].text
, NULL
);
2582 /* pop up the dialog */
2583 run_dlg (compl_dlg
);
2585 /* apply the choosen completion */
2586 if (compl_dlg
->ret_value
== B_ENTER
) {
2587 listbox_get_current (compl_list
, &curr
, NULL
);
2589 for (curr
+= word_len
; *curr
; curr
++)
2590 edit_insert (edit
, *curr
);
2593 /* destroy dialog before return */
2594 destroy_dlg (compl_dlg
);
2598 /* complete current word using regular expression search */
2599 /* backwards beginning at current cursor position */
2600 void edit_complete_word_cmd (WEdit
*edit
)
2602 int word_len
= 0, i
, num_compl
= 0, max_len
;
2603 long word_start
= 0;
2605 char match_expr
[MAX_REPL_LEN
];
2606 struct selection
compl[MAX_WORD_COMPLETIONS
]; /* completions */
2608 /* don't want to disturb another search */
2609 int old_rs
= replace_scanf
;
2610 int old_rb
= replace_backwards
;
2611 int old_rr
= replace_regexp
;
2612 int old_rw
= replace_whole
;
2613 int old_rc
= replace_case
;
2615 /* search start of word to be completed */
2616 if (!edit_find_word_start (edit
, &word_start
, &word_len
))
2619 /* prepare match expression */
2620 bufpos
= &edit
->buffers1
[word_start
>> S_EDIT_BUF_SIZE
]
2621 [word_start
& M_EDIT_BUF_SIZE
];
2622 strncpy (match_expr
, bufpos
, word_len
);
2623 match_expr
[word_len
] = '\0';
2624 strcat (match_expr
, "[a-zA-Z_0-9]+");
2626 /* init search: backward, regexp, whole word, case sensitive */
2627 edit_set_search_parameters (0, 1, 1, 1, 1);
2629 /* collect the possible completions */
2630 /* start search from curs1 down to begin of file */
2631 max_len
= edit_collect_completions (edit
, word_start
, word_len
,
2632 match_expr
, (struct selection
*) &compl, &num_compl
);
2634 if (num_compl
> 0) {
2635 /* insert completed word if there is only one match */
2636 if (num_compl
== 1) {
2637 for (i
= word_len
; i
< compl[0].len
; i
++)
2638 edit_insert (edit
, *(compl[0].text
+ i
));
2640 /* more than one possible completion => ask the user */
2642 /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
2643 /* !!! pressed again the selection dialog pops up, but that !!! */
2644 /* !!! seems to require a further internal state !!! */
2647 /* let the user select the preferred completion */
2648 edit_completion_dialog (edit
, max_len
, word_len
,
2649 (struct selection
*) &compl, num_compl
);
2653 /* release memory before return */
2654 for (i
= 0; i
< num_compl
; i
++)
2655 free (compl[i
].text
);
2657 /* restore search parameters */
2658 edit_set_search_parameters (old_rs
, old_rb
, old_rr
, old_rw
, old_rc
);