Added function mc_build_filename() for processing URL-paths as well
[midnight-commander.git] / src / editor / edit.c
blob04d1553d32affac3825bd9b50549fdfc22ae6a21
1 /* editor low level data handling and cursor fundamentals.
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
6 Authors: Paul Sheer 1996, 1997
7 Ilia Maslakov <il.smind@gmail.com> 2009, 2010, 2011
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., 51 Franklin Street, Fifth Floor, Boston, MA
22 02110-1301, USA.
25 /** \file
26 * \brief Source: editor low level data handling and cursor fundamentals
27 * \author Paul Sheer
28 * \date 1996, 1997
31 #include <config.h>
32 #include <stdio.h>
33 #include <stdarg.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <sys/stat.h>
40 #include <stdlib.h>
41 #include <fcntl.h>
43 #include "lib/global.h"
45 #include "lib/tty/color.h"
46 #include "lib/tty/tty.h" /* attrset() */
47 #include "lib/tty/key.h" /* is_idle() */
48 #include "lib/skin.h" /* EDITOR_NORMAL_COLOR */
49 #include "lib/vfs/vfs.h"
50 #include "lib/strutil.h" /* utf string functions */
51 #include "lib/util.h" /* load_file_position(), save_file_position() */
52 #include "lib/timefmt.h" /* time formatting */
53 #include "lib/lock.h"
54 #include "lib/widget.h"
56 #ifdef HAVE_CHARSET
57 #include "lib/charsets.h" /* get_codepage_id */
58 #endif
60 #include "src/filemanager/cmd.h" /* view_other_cmd() */
61 #include "src/filemanager/usermenu.h" /* user_menu_cmd() */
63 #include "src/setup.h" /* option_tab_spacing */
64 #include "src/learn.h" /* learn_keys */
65 #include "src/keybind-defaults.h"
67 #include "edit-impl.h"
68 #include "edit-widget.h"
70 /*** global variables ****************************************************************************/
72 int option_word_wrap_line_length = DEFAULT_WRAP_LINE_LENGTH;
73 int option_typewriter_wrap = 0;
74 int option_auto_para_formatting = 0;
75 int option_fill_tabs_with_spaces = 0;
76 int option_return_does_auto_indent = 1;
77 int option_backspace_through_tabs = 0;
78 int option_fake_half_tabs = 1;
79 int option_save_mode = EDIT_QUICK_SAVE;
80 int option_save_position = 1;
81 int option_max_undo = 32768;
82 int option_persistent_selections = 1;
83 int option_cursor_beyond_eol = 0;
84 int option_line_state = 0;
85 int option_line_state_width = 0;
87 int option_edit_right_extreme = 0;
88 int option_edit_left_extreme = 0;
89 int option_edit_top_extreme = 0;
90 int option_edit_bottom_extreme = 0;
91 int enable_show_tabs_tws = 1;
92 int option_check_nl_at_eof = 0;
93 int option_group_undo = 0;
94 int show_right_margin = 0;
96 const char *option_whole_chars_search = "0123456789abcdefghijklmnopqrstuvwxyz_";
97 char *option_backup_ext = NULL;
99 int edit_stack_iterator = 0;
100 edit_stack_type edit_history_moveto[MAX_HISTORY_MOVETO];
101 /* magic sequense for say than block is vertical */
102 const char VERTICAL_MAGIC[] = { '\1', '\1', '\1', '\1', '\n' };
104 /*** file scope macro definitions ****************************************************************/
106 #define TEMP_BUF_LEN 1024
108 #define space_width 1
110 /*** file scope type declarations ****************************************************************/
112 /*** file scope variables ************************************************************************/
114 /* detecting an error on save is easy: just check if every byte has been written. */
115 /* detecting an error on read, is not so easy 'cos there is not way to tell
116 whether you read everything or not. */
117 /* FIXME: add proper `triple_pipe_open' to read, write and check errors. */
118 static const struct edit_filters
120 const char *read, *write, *extension;
121 } all_filters[] =
123 /* *INDENT-OFF* */
124 { "xz -cd %s 2>&1", "xz > %s", ".xz"},
125 { "lzma -cd %s 2>&1", "lzma > %s", ".lzma" },
126 { "bzip2 -cd %s 2>&1", "bzip2 > %s", ".bz2" },
127 { "gzip -cd %s 2>&1", "gzip > %s", ".gz" },
128 { "gzip -cd %s 2>&1", "gzip > %s", ".Z" }
129 /* *INDENT-ON* */
132 static long last_bracket = -1;
134 /*** file scope functions ************************************************************************/
135 /* --------------------------------------------------------------------------------------------- */
139 * here's a quick sketch of the layout: (don't run this through indent.)
141 * (b1 is buffers1 and b2 is buffers2)
144 * \0\0\0\0\0m e _ f i l e . \nf i n . \n|T h i s _ i s _ s o\0\0\0\0\0\0\0\0\0
145 * ______________________________________|______________________________________
147 * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
148 * |-> |-> |-> |-> |-> |-> |
150 * _<------------------------->|<----------------->_
151 * WEdit->curs2 | WEdit->curs1
152 * ^ | ^
153 * | ^|^ |
154 * cursor ||| cursor
155 * |||
156 * file end|||file beginning
161 * This_is_some_file
162 * fin.
165 /* --------------------------------------------------------------------------------------------- */
167 static int left_of_four_spaces (WEdit * edit);
169 /* --------------------------------------------------------------------------------------------- */
171 static void
172 edit_about (void)
174 const char *header = N_("About");
175 const char *button_name = N_("&OK");
176 const char *const version = "MCEdit " VERSION;
177 char text[BUF_LARGE];
179 int win_len, version_len, button_len;
180 int cols, lines;
182 Dlg_head *about_dlg;
184 #ifdef ENABLE_NLS
185 header = _(header);
186 button_name = _(button_name);
187 #endif
189 button_len = str_term_width1 (button_name) + 5;
190 version_len = str_term_width1 (version);
192 g_snprintf (text, sizeof (text),
193 _("Copyright (C) 1996-2010 the Free Software Foundation\n\n"
194 " A user friendly text editor\n"
195 " written for the Midnight Commander"));
197 win_len = str_term_width1 (header);
198 win_len = max (win_len, version_len);
199 win_len = max (win_len, button_len);
201 /* count width and height of text */
202 str_msg_term_size (text, &lines, &cols);
203 lines += 9;
204 cols = max (win_len, cols) + 6;
206 /* dialog */
207 about_dlg = create_dlg (TRUE, 0, 0, lines, cols, dialog_colors, NULL,
208 "[Internal File Editor]", header, DLG_CENTER | DLG_TRYUP);
210 add_widget (about_dlg, label_new (3, (cols - version_len) / 2, version));
211 add_widget (about_dlg, label_new (5, 3, text));
212 add_widget (about_dlg, button_new (lines - 3, (cols - button_len) / 2,
213 B_ENTER, NORMAL_BUTTON, button_name, NULL));
215 run_dlg (about_dlg);
216 destroy_dlg (about_dlg);
219 /* --------------------------------------------------------------------------------------------- */
221 * Initialize the buffers for an empty files.
224 static void
225 edit_init_buffers (WEdit * edit)
227 int j;
229 for (j = 0; j <= MAXBUFF; j++)
231 edit->buffers1[j] = NULL;
232 edit->buffers2[j] = NULL;
235 edit->curs1 = 0;
236 edit->curs2 = 0;
237 edit->buffers2[0] = g_malloc0 (EDIT_BUF_SIZE);
240 /* --------------------------------------------------------------------------------------------- */
242 * Load file OR text into buffers. Set cursor to the beginning of file.
243 * @returns 1 on error.
246 static int
247 edit_load_file_fast (WEdit * edit, const char *filename)
249 long buf, buf2;
250 int file = -1;
251 int ret = 1;
253 edit->curs2 = edit->last_byte;
254 buf2 = edit->curs2 >> S_EDIT_BUF_SIZE;
256 file = mc_open (filename, O_RDONLY | O_BINARY);
257 if (file == -1)
259 gchar *errmsg;
261 errmsg = g_strdup_printf (_("Cannot open %s for reading"), filename);
262 edit_error_dialog (_("Error"), errmsg);
263 g_free (errmsg);
264 return 1;
267 if (!edit->buffers2[buf2])
268 edit->buffers2[buf2] = g_malloc0 (EDIT_BUF_SIZE);
272 if (mc_read (file,
273 (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE -
274 (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE) < 0)
275 break;
277 for (buf = buf2 - 1; buf >= 0; buf--)
279 /* edit->buffers2[0] is already allocated */
280 if (!edit->buffers2[buf])
281 edit->buffers2[buf] = g_malloc0 (EDIT_BUF_SIZE);
282 if (mc_read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) < 0)
283 break;
285 ret = 0;
287 while (0);
288 if (ret)
290 char *err_str = g_strdup_printf (_("Error reading %s"), filename);
291 edit_error_dialog (_("Error"), err_str);
292 g_free (err_str);
294 mc_close (file);
295 return ret;
298 /* --------------------------------------------------------------------------------------------- */
299 /** Return index of the filter or -1 is there is no appropriate filter */
301 static int
302 edit_find_filter (const char *filename)
304 size_t i, l, e;
306 if (filename == NULL)
307 return -1;
309 l = strlen (filename);
310 for (i = 0; i < sizeof (all_filters) / sizeof (all_filters[0]); i++)
312 e = strlen (all_filters[i].extension);
313 if (l > e)
314 if (!strcmp (all_filters[i].extension, filename + l - e))
315 return i;
317 return -1;
320 /* --------------------------------------------------------------------------------------------- */
322 static char *
323 edit_get_filter (const char *filename)
325 int i;
326 char *p, *quoted_name;
328 i = edit_find_filter (filename);
329 if (i < 0)
330 return NULL;
332 quoted_name = name_quote (filename, 0);
333 p = g_strdup_printf (all_filters[i].read, quoted_name);
334 g_free (quoted_name);
335 return p;
338 /* --------------------------------------------------------------------------------------------- */
340 static long
341 edit_insert_stream (WEdit * edit, FILE * f)
343 int c;
344 long i = 0;
345 while ((c = fgetc (f)) >= 0)
347 edit_insert (edit, c);
348 i++;
350 return i;
353 /* --------------------------------------------------------------------------------------------- */
354 /** Open file and create it if necessary. Return 0 for success, 1 for error. */
356 static int
357 check_file_access (WEdit * edit, const char *filename, struct stat *st)
359 int file;
360 gchar *errmsg = NULL;
362 /* Try opening an existing file */
363 file = mc_open (filename, O_NONBLOCK | O_RDONLY | O_BINARY, 0666);
365 if (file < 0)
368 * Try creating the file. O_EXCL prevents following broken links
369 * and opening existing files.
371 file = mc_open (filename, O_NONBLOCK | O_RDONLY | O_BINARY | O_CREAT | O_EXCL, 0666);
372 if (file < 0)
374 errmsg = g_strdup_printf (_("Cannot open %s for reading"), filename);
375 goto cleanup;
377 else
379 /* New file, delete it if it's not modified or saved */
380 edit->delete_file = 1;
384 /* Check what we have opened */
385 if (mc_fstat (file, st) < 0)
387 errmsg = g_strdup_printf (_("Cannot get size/permissions for %s"), filename);
388 goto cleanup;
391 /* We want to open regular files only */
392 if (!S_ISREG (st->st_mode))
394 errmsg = g_strdup_printf (_("\"%s\" is not a regular file"), filename);
395 goto cleanup;
399 * Don't delete non-empty files.
400 * O_EXCL should prevent it, but let's be on the safe side.
402 if (st->st_size > 0)
403 edit->delete_file = 0;
405 if (st->st_size >= SIZE_LIMIT)
406 errmsg = g_strdup_printf (_("File \"%s\" is too large"), filename);
408 cleanup:
409 (void) mc_close (file);
411 if (errmsg != NULL)
413 edit_error_dialog (_("Error"), errmsg);
414 g_free (errmsg);
415 return 1;
417 return 0;
420 /* --------------------------------------------------------------------------------------------- */
422 * Open the file and load it into the buffers, either directly or using
423 * a filter. Return 0 on success, 1 on error.
425 * Fast loading (edit_load_file_fast) is used when the file size is
426 * known. In this case the data is read into the buffers by blocks.
427 * If the file size is not known, the data is loaded byte by byte in
428 * edit_insert_file.
431 static int
432 edit_load_file (WEdit * edit)
434 int fast_load = 1;
435 vfs_path_t *vpath = vfs_path_from_str (edit->filename);
437 /* Cannot do fast load if a filter is used */
438 if (edit_find_filter (edit->filename) >= 0)
439 fast_load = 0;
442 * VFS may report file size incorrectly, and slow load is not a big
443 * deal considering overhead in VFS.
445 if (!vfs_file_is_local (vpath))
446 fast_load = 0;
447 vfs_path_free (vpath);
450 * FIXME: line end translation should disable fast loading as well
451 * Consider doing fseek() to the end and ftell() for the real size.
454 if (*edit->filename)
456 /* If we are dealing with a real file, check that it exists */
457 if (check_file_access (edit, edit->filename, &edit->stat1))
458 return 1;
460 else
462 /* nothing to load */
463 fast_load = 0;
466 edit_init_buffers (edit);
468 if (fast_load)
470 edit->last_byte = edit->stat1.st_size;
471 edit_load_file_fast (edit, edit->filename);
472 /* If fast load was used, the number of lines wasn't calculated */
473 edit->total_lines = edit_count_lines (edit, 0, edit->last_byte);
475 else
477 edit->last_byte = 0;
478 if (*edit->filename)
480 edit->undo_stack_disable = 1;
481 if (edit_insert_file (edit, edit->filename) == 0)
483 edit_clean (edit);
484 return 1;
486 edit->undo_stack_disable = 0;
489 edit->lb = LB_ASIS;
490 return 0;
493 /* --------------------------------------------------------------------------------------------- */
494 /** Restore saved cursor position in the file */
496 static void
497 edit_load_position (WEdit * edit)
499 char *filename;
500 long line, column;
501 off_t offset;
502 vfs_path_t *vpath;
504 if (!edit->filename || !*edit->filename)
505 return;
507 vpath = vfs_path_from_str (edit->filename);
508 filename = vfs_path_to_str (vpath);
509 load_file_position (filename, &line, &column, &offset, &edit->serialized_bookmarks);
510 vfs_path_free (vpath);
511 g_free (filename);
513 if (line > 0)
515 edit_move_to_line (edit, line - 1);
516 edit->prev_col = column;
518 else if (offset > 0)
520 edit_cursor_move (edit, offset);
521 line = edit->curs_line;
522 edit->search_start = edit->curs1;
525 book_mark_restore (edit, BOOK_MARK_COLOR);
527 edit_move_to_prev_col (edit, edit_bol (edit, edit->curs1));
528 edit_move_display (edit, line - (edit->widget.lines / 2));
531 /* --------------------------------------------------------------------------------------------- */
532 /** Save cursor position in the file */
534 static void
535 edit_save_position (WEdit * edit)
537 char *filename;
538 vfs_path_t *vpath;
540 if (edit->filename == NULL || *edit->filename == '\0')
541 return;
543 vpath = vfs_path_from_str (edit->filename);
544 filename = vfs_path_to_str (vpath);
546 book_mark_serialize (edit, BOOK_MARK_COLOR);
547 save_file_position (filename, edit->curs_line + 1, edit->curs_col, edit->curs1,
548 edit->serialized_bookmarks);
549 edit->serialized_bookmarks = NULL;
551 g_free (filename);
552 vfs_path_free (vpath);
555 /* --------------------------------------------------------------------------------------------- */
556 /** Clean the WEdit stricture except the widget part */
558 static void
559 edit_purge_widget (WEdit * edit)
561 size_t len = sizeof (WEdit) - sizeof (Widget);
562 char *start = (char *) edit + sizeof (Widget);
563 memset (start, 0, len);
566 /* --------------------------------------------------------------------------------------------- */
569 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
570 then the file should be as it was when he loaded up. Then set edit->modified to 0.
573 static long
574 edit_pop_undo_action (WEdit * edit)
576 long c;
577 unsigned long sp = edit->undo_stack_pointer;
579 if (sp == edit->undo_stack_bottom)
580 return STACK_BOTTOM;
582 sp = (sp - 1) & edit->undo_stack_size_mask;
583 c = edit->undo_stack[sp];
584 if (c >= 0)
586 /* edit->undo_stack[sp] = '@'; */
587 edit->undo_stack_pointer = (edit->undo_stack_pointer - 1) & edit->undo_stack_size_mask;
588 return c;
591 if (sp == edit->undo_stack_bottom)
592 return STACK_BOTTOM;
594 c = edit->undo_stack[(sp - 1) & edit->undo_stack_size_mask];
595 if (edit->undo_stack[sp] == -2)
597 /* edit->undo_stack[sp] = '@'; */
598 edit->undo_stack_pointer = sp;
600 else
601 edit->undo_stack[sp]++;
603 return c;
606 static long
607 edit_pop_redo_action (WEdit * edit)
609 long c;
610 unsigned long sp = edit->redo_stack_pointer;
612 if (sp == edit->redo_stack_bottom)
613 return STACK_BOTTOM;
615 sp = (sp - 1) & edit->redo_stack_size_mask;
616 c = edit->redo_stack[sp];
617 if (c >= 0)
619 edit->redo_stack_pointer = (edit->redo_stack_pointer - 1) & edit->redo_stack_size_mask;
620 return c;
623 if (sp == edit->redo_stack_bottom)
624 return STACK_BOTTOM;
626 c = edit->redo_stack[(sp - 1) & edit->redo_stack_size_mask];
627 if (edit->redo_stack[sp] == -2)
628 edit->redo_stack_pointer = sp;
629 else
630 edit->redo_stack[sp]++;
632 return c;
635 static long
636 get_prev_undo_action (WEdit * edit)
638 long c;
639 unsigned long sp = edit->undo_stack_pointer;
641 if (sp == edit->undo_stack_bottom)
642 return STACK_BOTTOM;
644 sp = (sp - 1) & edit->undo_stack_size_mask;
645 c = edit->undo_stack[sp];
646 if (c >= 0)
647 return c;
649 if (sp == edit->undo_stack_bottom)
650 return STACK_BOTTOM;
652 c = edit->undo_stack[(sp - 1) & edit->undo_stack_size_mask];
653 return c;
656 /* --------------------------------------------------------------------------------------------- */
657 /** is called whenever a modification is made by one of the four routines below */
659 static void
660 edit_modification (WEdit * edit)
662 edit->caches_valid = 0;
664 /* raise lock when file modified */
665 if (!edit->modified && !edit->delete_file)
666 edit->locked = edit_lock_file (edit);
667 edit->modified = 1;
670 /* --------------------------------------------------------------------------------------------- */
672 static int
673 edit_backspace (WEdit * edit, const int byte_delete)
675 int p = 0;
676 int cw = 1;
677 int i;
679 if (!edit->curs1)
680 return 0;
682 cw = 1;
684 if (edit->mark2 != edit->mark1)
685 edit_push_markers (edit);
687 if (edit->utf8 && byte_delete == 0)
689 edit_get_prev_utf (edit, edit->curs1, &cw);
690 if (cw < 1)
691 cw = 1;
693 for (i = 1; i <= cw; i++)
695 if (edit->mark1 >= edit->curs1)
697 edit->mark1--;
698 edit->end_mark_curs--;
700 if (edit->mark2 >= edit->curs1)
701 edit->mark2--;
702 if (edit->last_get_rule >= edit->curs1)
703 edit->last_get_rule--;
705 p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] +
706 ((edit->curs1 - 1) & M_EDIT_BUF_SIZE));
707 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE))
709 g_free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
710 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
712 edit->last_byte--;
713 edit->curs1--;
714 edit_push_undo_action (edit, p);
716 edit_modification (edit);
717 if (p == '\n')
719 if (edit->book_mark)
720 book_mark_dec (edit, edit->curs_line);
721 edit->curs_line--;
722 edit->total_lines--;
723 edit->force |= REDRAW_AFTER_CURSOR;
726 if (edit->curs1 < edit->start_display)
728 edit->start_display--;
729 if (p == '\n')
730 edit->start_line--;
733 return p;
736 /* --------------------------------------------------------------------------------------------- */
737 /* high level cursor movement commands */
738 /* --------------------------------------------------------------------------------------------- */
740 static int
741 is_in_indent (WEdit * edit)
743 long p = edit_bol (edit, edit->curs1);
744 while (p < edit->curs1)
745 if (!strchr (" \t", edit_get_byte (edit, p++)))
746 return 0;
747 return 1;
750 /* --------------------------------------------------------------------------------------------- */
752 static int
753 is_blank (WEdit * edit, long offset)
755 long s, f;
756 int c;
757 s = edit_bol (edit, offset);
758 f = edit_eol (edit, offset) - 1;
759 while (s <= f)
761 c = edit_get_byte (edit, s++);
762 if (!isspace (c))
763 return 0;
765 return 1;
769 /* --------------------------------------------------------------------------------------------- */
770 /** returns the offset of line i */
772 static long
773 edit_find_line (WEdit * edit, int line)
775 int i, j = 0;
776 int m = 2000000000;
777 if (!edit->caches_valid)
779 for (i = 0; i < N_LINE_CACHES; i++)
780 edit->line_numbers[i] = edit->line_offsets[i] = 0;
781 /* three offsets that we *know* are line 0 at 0 and these two: */
782 edit->line_numbers[1] = edit->curs_line;
783 edit->line_offsets[1] = edit_bol (edit, edit->curs1);
784 edit->line_numbers[2] = edit->total_lines;
785 edit->line_offsets[2] = edit_bol (edit, edit->last_byte);
786 edit->caches_valid = 1;
788 if (line >= edit->total_lines)
789 return edit->line_offsets[2];
790 if (line <= 0)
791 return 0;
792 /* find the closest known point */
793 for (i = 0; i < N_LINE_CACHES; i++)
795 int n;
796 n = abs (edit->line_numbers[i] - line);
797 if (n < m)
799 m = n;
800 j = i;
803 if (m == 0)
804 return edit->line_offsets[j]; /* know the offset exactly */
805 if (m == 1 && j >= 3)
806 i = j; /* one line different - caller might be looping, so stay in this cache */
807 else
808 i = 3 + (rand () % (N_LINE_CACHES - 3));
809 if (line > edit->line_numbers[j])
810 edit->line_offsets[i] =
811 edit_move_forward (edit, edit->line_offsets[j], line - edit->line_numbers[j], 0);
812 else
813 edit->line_offsets[i] =
814 edit_move_backward (edit, edit->line_offsets[j], edit->line_numbers[j] - line);
815 edit->line_numbers[i] = line;
816 return edit->line_offsets[i];
819 /* --------------------------------------------------------------------------------------------- */
820 /** moves up until a blank line is reached, or until just
821 before a non-blank line is reached */
823 static void
824 edit_move_up_paragraph (WEdit * edit, int do_scroll)
826 int i = 0;
827 if (edit->curs_line > 1)
829 if (line_is_blank (edit, edit->curs_line))
831 if (line_is_blank (edit, edit->curs_line - 1))
833 for (i = edit->curs_line - 1; i; i--)
834 if (!line_is_blank (edit, i))
836 i++;
837 break;
840 else
842 for (i = edit->curs_line - 1; i; i--)
843 if (line_is_blank (edit, i))
844 break;
847 else
849 for (i = edit->curs_line - 1; i; i--)
850 if (line_is_blank (edit, i))
851 break;
854 edit_move_up (edit, edit->curs_line - i, do_scroll);
857 /* --------------------------------------------------------------------------------------------- */
858 /** moves down until a blank line is reached, or until just
859 before a non-blank line is reached */
861 static void
862 edit_move_down_paragraph (WEdit * edit, int do_scroll)
864 int i;
865 if (edit->curs_line >= edit->total_lines - 1)
867 i = edit->total_lines;
869 else
871 if (line_is_blank (edit, edit->curs_line))
873 if (line_is_blank (edit, edit->curs_line + 1))
875 for (i = edit->curs_line + 1; i; i++)
876 if (!line_is_blank (edit, i) || i > edit->total_lines)
878 i--;
879 break;
882 else
884 for (i = edit->curs_line + 1; i; i++)
885 if (line_is_blank (edit, i) || i >= edit->total_lines)
886 break;
889 else
891 for (i = edit->curs_line + 1; i; i++)
892 if (line_is_blank (edit, i) || i >= edit->total_lines)
893 break;
896 edit_move_down (edit, i - edit->curs_line, do_scroll);
899 /* --------------------------------------------------------------------------------------------- */
901 static void
902 edit_begin_page (WEdit * edit)
904 edit_update_curs_row (edit);
905 edit_move_up (edit, edit->curs_row, 0);
908 /* --------------------------------------------------------------------------------------------- */
910 static void
911 edit_end_page (WEdit * edit)
913 edit_update_curs_row (edit);
914 edit_move_down (edit, edit->widget.lines - edit->curs_row - 1, 0);
918 /* --------------------------------------------------------------------------------------------- */
919 /** goto beginning of text */
921 static void
922 edit_move_to_top (WEdit * edit)
924 if (edit->curs_line)
926 edit_cursor_move (edit, -edit->curs1);
927 edit_move_to_prev_col (edit, 0);
928 edit->force |= REDRAW_PAGE;
929 edit->search_start = 0;
930 edit_update_curs_row (edit);
935 /* --------------------------------------------------------------------------------------------- */
936 /** goto end of text */
938 static void
939 edit_move_to_bottom (WEdit * edit)
941 if (edit->curs_line < edit->total_lines)
943 edit_move_down (edit, edit->total_lines - edit->curs_row, 0);
944 edit->start_display = edit->last_byte;
945 edit->start_line = edit->total_lines;
946 edit_scroll_upward (edit, edit->widget.lines - 1);
947 edit->force |= REDRAW_PAGE;
951 /* --------------------------------------------------------------------------------------------- */
952 /** goto beginning of line */
954 static void
955 edit_cursor_to_bol (WEdit * edit)
957 edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
958 edit->search_start = edit->curs1;
959 edit->prev_col = edit_get_col (edit);
960 edit->over_col = 0;
963 /* --------------------------------------------------------------------------------------------- */
964 /** goto end of line */
966 static void
967 edit_cursor_to_eol (WEdit * edit)
969 edit_cursor_move (edit, edit_eol (edit, edit->curs1) - edit->curs1);
970 edit->search_start = edit->curs1;
971 edit->prev_col = edit_get_col (edit);
972 edit->over_col = 0;
975 /* --------------------------------------------------------------------------------------------- */
977 static unsigned long
978 my_type_of (int c)
980 int x, r = 0;
981 const char *p, *q;
982 const char option_chars_move_whole_word[] =
983 "!=&|<>^~ !:;, !'!`!.?!\"!( !) !{ !} !Aa0 !+-*/= |<> ![ !] !\\#! ";
985 if (!c)
986 return 0;
987 if (c == '!')
989 if (*option_chars_move_whole_word == '!')
990 return 2;
991 return 0x80000000UL;
993 if (g_ascii_isupper ((gchar) c))
994 c = 'A';
995 else if (g_ascii_islower ((gchar) c))
996 c = 'a';
997 else if (g_ascii_isalpha (c))
998 c = 'a';
999 else if (isdigit (c))
1000 c = '0';
1001 else if (isspace (c))
1002 c = ' ';
1003 q = strchr (option_chars_move_whole_word, c);
1004 if (!q)
1005 return 0xFFFFFFFFUL;
1008 for (x = 1, p = option_chars_move_whole_word; p < q; p++)
1009 if (*p == '!')
1010 x <<= 1;
1011 r |= x;
1013 while ((q = strchr (q + 1, c)));
1014 return r;
1017 /* --------------------------------------------------------------------------------------------- */
1019 static void
1020 edit_left_word_move (WEdit * edit, int s)
1022 for (;;)
1024 int c1, c2;
1025 if (edit->column_highlight
1026 && edit->mark1 != edit->mark2
1027 && edit->over_col == 0 && edit->curs1 == edit_bol (edit, edit->curs1))
1028 break;
1029 edit_cursor_move (edit, -1);
1030 if (!edit->curs1)
1031 break;
1032 c1 = edit_get_byte (edit, edit->curs1 - 1);
1033 c2 = edit_get_byte (edit, edit->curs1);
1034 if (c1 == '\n' || c2 == '\n')
1035 break;
1036 if (!(my_type_of (c1) & my_type_of (c2)))
1037 break;
1038 if (isspace (c1) && !isspace (c2))
1039 break;
1040 if (s)
1041 if (!isspace (c1) && isspace (c2))
1042 break;
1046 /* --------------------------------------------------------------------------------------------- */
1048 static void
1049 edit_left_word_move_cmd (WEdit * edit)
1051 edit_left_word_move (edit, 0);
1052 edit->force |= REDRAW_PAGE;
1055 /* --------------------------------------------------------------------------------------------- */
1057 static void
1058 edit_right_word_move (WEdit * edit, int s)
1060 for (;;)
1062 int c1, c2;
1063 if (edit->column_highlight
1064 && edit->mark1 != edit->mark2
1065 && edit->over_col == 0 && edit->curs1 == edit_eol (edit, edit->curs1))
1066 break;
1067 edit_cursor_move (edit, 1);
1068 if (edit->curs1 >= edit->last_byte)
1069 break;
1070 c1 = edit_get_byte (edit, edit->curs1 - 1);
1071 c2 = edit_get_byte (edit, edit->curs1);
1072 if (c1 == '\n' || c2 == '\n')
1073 break;
1074 if (!(my_type_of (c1) & my_type_of (c2)))
1075 break;
1076 if (isspace (c1) && !isspace (c2))
1077 break;
1078 if (s)
1079 if (!isspace (c1) && isspace (c2))
1080 break;
1084 /* --------------------------------------------------------------------------------------------- */
1086 static void
1087 edit_right_word_move_cmd (WEdit * edit)
1089 edit_right_word_move (edit, 0);
1090 edit->force |= REDRAW_PAGE;
1093 /* --------------------------------------------------------------------------------------------- */
1095 static void
1096 edit_right_char_move_cmd (WEdit * edit)
1098 int cw = 1;
1099 int c = 0;
1100 if (edit->utf8)
1102 c = edit_get_utf (edit, edit->curs1, &cw);
1103 if (cw < 1)
1104 cw = 1;
1106 else
1108 c = edit_get_byte (edit, edit->curs1);
1110 if (option_cursor_beyond_eol && c == '\n')
1112 edit->over_col++;
1114 else
1116 edit_cursor_move (edit, cw);
1120 /* --------------------------------------------------------------------------------------------- */
1122 static void
1123 edit_left_char_move_cmd (WEdit * edit)
1125 int cw = 1;
1126 if (edit->column_highlight
1127 && option_cursor_beyond_eol
1128 && edit->mark1 != edit->mark2
1129 && edit->over_col == 0 && edit->curs1 == edit_bol (edit, edit->curs1))
1130 return;
1131 if (edit->utf8)
1133 edit_get_prev_utf (edit, edit->curs1, &cw);
1134 if (cw < 1)
1135 cw = 1;
1137 if (option_cursor_beyond_eol && edit->over_col > 0)
1139 edit->over_col--;
1141 else
1143 edit_cursor_move (edit, -cw);
1147 /* --------------------------------------------------------------------------------------------- */
1148 /** Up or down cursor moving.
1149 direction = TRUE - move up
1150 = FALSE - move down
1153 static void
1154 edit_move_updown (WEdit * edit, unsigned long i, int do_scroll, gboolean direction)
1156 unsigned long p;
1157 unsigned long l = (direction) ? edit->curs_line : edit->total_lines - edit->curs_line;
1159 if (i > l)
1160 i = l;
1162 if (i == 0)
1163 return;
1165 if (i > 1)
1166 edit->force |= REDRAW_PAGE;
1167 if (do_scroll)
1169 if (direction)
1170 edit_scroll_upward (edit, i);
1171 else
1172 edit_scroll_downward (edit, i);
1174 p = edit_bol (edit, edit->curs1);
1176 p = (direction) ? edit_move_backward (edit, p, i) : edit_move_forward (edit, p, i, 0);
1178 edit_cursor_move (edit, p - edit->curs1);
1180 edit_move_to_prev_col (edit, p);
1182 /* search start of current multibyte char (like CJK) */
1183 if (edit->curs1 + 1 < edit->last_byte)
1185 edit_right_char_move_cmd (edit);
1186 edit_left_char_move_cmd (edit);
1189 edit->search_start = edit->curs1;
1190 edit->found_len = 0;
1193 /* --------------------------------------------------------------------------------------------- */
1195 static void
1196 edit_right_delete_word (WEdit * edit)
1198 int c1, c2;
1199 for (;;)
1201 if (edit->curs1 >= edit->last_byte)
1202 break;
1203 c1 = edit_delete (edit, 1);
1204 c2 = edit_get_byte (edit, edit->curs1);
1205 if (c1 == '\n' || c2 == '\n')
1206 break;
1207 if ((isspace (c1) == 0) != (isspace (c2) == 0))
1208 break;
1209 if (!(my_type_of (c1) & my_type_of (c2)))
1210 break;
1214 /* --------------------------------------------------------------------------------------------- */
1216 static void
1217 edit_left_delete_word (WEdit * edit)
1219 int c1, c2;
1220 for (;;)
1222 if (edit->curs1 <= 0)
1223 break;
1224 c1 = edit_backspace (edit, 1);
1225 c2 = edit_get_byte (edit, edit->curs1 - 1);
1226 if (c1 == '\n' || c2 == '\n')
1227 break;
1228 if ((isspace (c1) == 0) != (isspace (c2) == 0))
1229 break;
1230 if (!(my_type_of (c1) & my_type_of (c2)))
1231 break;
1235 /* --------------------------------------------------------------------------------------------- */
1237 the start column position is not recorded, and hence does not
1238 undo as it happed. But who would notice.
1241 static void
1242 edit_do_undo (WEdit * edit)
1244 long ac;
1245 long count = 0;
1247 edit->undo_stack_disable = 1; /* don't record undo's onto undo stack! */
1248 edit->over_col = 0;
1249 while ((ac = edit_pop_undo_action (edit)) < KEY_PRESS)
1251 switch ((int) ac)
1253 case STACK_BOTTOM:
1254 goto done_undo;
1255 case CURS_RIGHT:
1256 edit_cursor_move (edit, 1);
1257 break;
1258 case CURS_LEFT:
1259 edit_cursor_move (edit, -1);
1260 break;
1261 case BACKSPACE:
1262 case BACKSPACE_BR:
1263 edit_backspace (edit, 1);
1264 break;
1265 case DELCHAR:
1266 case DELCHAR_BR:
1267 edit_delete (edit, 1);
1268 break;
1269 case COLUMN_ON:
1270 edit->column_highlight = 1;
1271 break;
1272 case COLUMN_OFF:
1273 edit->column_highlight = 0;
1274 break;
1276 if (ac >= 256 && ac < 512)
1277 edit_insert_ahead (edit, ac - 256);
1278 if (ac >= 0 && ac < 256)
1279 edit_insert (edit, ac);
1281 if (ac >= MARK_1 - 2 && ac < MARK_2 - 2)
1283 edit->mark1 = ac - MARK_1;
1284 edit->column1 = edit_move_forward3 (edit, edit_bol (edit, edit->mark1), 0, edit->mark1);
1286 if (ac >= MARK_2 - 2 && ac < MARK_CURS - 2)
1288 edit->mark2 = ac - MARK_2;
1289 edit->column2 = edit_move_forward3 (edit, edit_bol (edit, edit->mark2), 0, edit->mark2);
1291 else if (ac >= MARK_CURS - 2 && ac < KEY_PRESS)
1293 edit->end_mark_curs = ac - MARK_CURS;
1295 if (count++)
1296 edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
1299 if (edit->start_display > ac - KEY_PRESS)
1301 edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display);
1302 edit->force |= REDRAW_PAGE;
1304 else if (edit->start_display < ac - KEY_PRESS)
1306 edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS);
1307 edit->force |= REDRAW_PAGE;
1309 edit->start_display = ac - KEY_PRESS; /* see push and pop above */
1310 edit_update_curs_row (edit);
1312 done_undo:;
1313 edit->undo_stack_disable = 0;
1316 static void
1317 edit_do_redo (WEdit * edit)
1319 long ac;
1320 long count = 0;
1322 if (edit->redo_stack_reset)
1323 return;
1325 edit->over_col = 0;
1326 while ((ac = edit_pop_redo_action (edit)) < KEY_PRESS)
1328 switch ((int) ac)
1330 case STACK_BOTTOM:
1331 goto done_redo;
1332 case CURS_RIGHT:
1333 edit_cursor_move (edit, 1);
1334 break;
1335 case CURS_LEFT:
1336 edit_cursor_move (edit, -1);
1337 break;
1338 case BACKSPACE:
1339 edit_backspace (edit, 1);
1340 break;
1341 case DELCHAR:
1342 edit_delete (edit, 1);
1343 break;
1344 case COLUMN_ON:
1345 edit->column_highlight = 1;
1346 break;
1347 case COLUMN_OFF:
1348 edit->column_highlight = 0;
1349 break;
1351 if (ac >= 256 && ac < 512)
1352 edit_insert_ahead (edit, ac - 256);
1353 if (ac >= 0 && ac < 256)
1354 edit_insert (edit, ac);
1356 if (ac >= MARK_1 - 2 && ac < MARK_2 - 2)
1358 edit->mark1 = ac - MARK_1;
1359 edit->column1 = edit_move_forward3 (edit, edit_bol (edit, edit->mark1), 0, edit->mark1);
1361 else if (ac >= MARK_2 - 2 && ac < KEY_PRESS)
1363 edit->mark2 = ac - MARK_2;
1364 edit->column2 = edit_move_forward3 (edit, edit_bol (edit, edit->mark2), 0, edit->mark2);
1366 /* more than one pop usually means something big */
1367 if (count++)
1368 edit->force |= REDRAW_PAGE;
1371 if (edit->start_display > ac - KEY_PRESS)
1373 edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display);
1374 edit->force |= REDRAW_PAGE;
1376 else if (edit->start_display < ac - KEY_PRESS)
1378 edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS);
1379 edit->force |= REDRAW_PAGE;
1381 edit->start_display = ac - KEY_PRESS; /* see push and pop above */
1382 edit_update_curs_row (edit);
1384 done_redo:;
1387 static void
1388 edit_group_undo (WEdit * edit)
1390 long ac = KEY_PRESS;
1391 long cur_ac = KEY_PRESS;
1392 while (ac != STACK_BOTTOM && ac == cur_ac)
1394 cur_ac = get_prev_undo_action (edit);
1395 edit_do_undo (edit);
1396 ac = get_prev_undo_action (edit);
1397 /* exit from cycle if option_group_undo is not set,
1398 * and make single UNDO operation
1400 if (!option_group_undo)
1401 ac = STACK_BOTTOM;
1405 /* --------------------------------------------------------------------------------------------- */
1407 static void
1408 edit_delete_to_line_end (WEdit * edit)
1410 while (edit_get_byte (edit, edit->curs1) != '\n')
1412 if (!edit->curs2)
1413 break;
1414 edit_delete (edit, 1);
1418 /* --------------------------------------------------------------------------------------------- */
1420 static void
1421 edit_delete_to_line_begin (WEdit * edit)
1423 while (edit_get_byte (edit, edit->curs1 - 1) != '\n')
1425 if (!edit->curs1)
1426 break;
1427 edit_backspace (edit, 1);
1431 /* --------------------------------------------------------------------------------------------- */
1433 static int
1434 is_aligned_on_a_tab (WEdit * edit)
1436 edit_update_curs_col (edit);
1437 return !((edit->curs_col % (TAB_SIZE * space_width))
1438 && edit->curs_col % (TAB_SIZE * space_width) != (HALF_TAB_SIZE * space_width));
1441 /* --------------------------------------------------------------------------------------------- */
1443 static int
1444 right_of_four_spaces (WEdit * edit)
1446 int i, ch = 0;
1447 for (i = 1; i <= HALF_TAB_SIZE; i++)
1448 ch |= edit_get_byte (edit, edit->curs1 - i);
1449 if (ch == ' ')
1450 return is_aligned_on_a_tab (edit);
1451 return 0;
1454 /* --------------------------------------------------------------------------------------------- */
1456 static int
1457 left_of_four_spaces (WEdit * edit)
1459 int i, ch = 0;
1460 for (i = 0; i < HALF_TAB_SIZE; i++)
1461 ch |= edit_get_byte (edit, edit->curs1 + i);
1462 if (ch == ' ')
1463 return is_aligned_on_a_tab (edit);
1464 return 0;
1467 /* --------------------------------------------------------------------------------------------- */
1469 static void
1470 edit_auto_indent (WEdit * edit)
1472 long p;
1473 char c;
1474 p = edit->curs1;
1475 /* use the previous line as a template */
1476 p = edit_move_backward (edit, p, 1);
1477 /* copy the leading whitespace of the line */
1478 for (;;)
1479 { /* no range check - the line _is_ \n-terminated */
1480 c = edit_get_byte (edit, p++);
1481 if (c != ' ' && c != '\t')
1482 break;
1483 edit_insert (edit, c);
1487 /* --------------------------------------------------------------------------------------------- */
1489 static inline void
1490 edit_double_newline (WEdit * edit)
1492 edit_insert (edit, '\n');
1493 if (edit_get_byte (edit, edit->curs1) == '\n')
1494 return;
1495 if (edit_get_byte (edit, edit->curs1 - 2) == '\n')
1496 return;
1497 edit->force |= REDRAW_PAGE;
1498 edit_insert (edit, '\n');
1501 /* --------------------------------------------------------------------------------------------- */
1503 static inline void
1504 edit_tab_cmd (WEdit * edit)
1506 int i;
1508 if (option_fake_half_tabs)
1510 if (is_in_indent (edit))
1512 /*insert a half tab (usually four spaces) unless there is a
1513 half tab already behind, then delete it and insert a
1514 full tab. */
1515 if (!option_fill_tabs_with_spaces && right_of_four_spaces (edit))
1517 for (i = 1; i <= HALF_TAB_SIZE; i++)
1518 edit_backspace (edit, 1);
1519 edit_insert (edit, '\t');
1521 else
1523 insert_spaces_tab (edit, 1);
1525 return;
1528 if (option_fill_tabs_with_spaces)
1530 insert_spaces_tab (edit, 0);
1532 else
1534 edit_insert (edit, '\t');
1538 /* --------------------------------------------------------------------------------------------- */
1540 static void
1541 check_and_wrap_line (WEdit * edit)
1543 int curs, c;
1544 if (!option_typewriter_wrap)
1545 return;
1546 edit_update_curs_col (edit);
1547 if (edit->curs_col < option_word_wrap_line_length)
1548 return;
1549 curs = edit->curs1;
1550 for (;;)
1552 curs--;
1553 c = edit_get_byte (edit, curs);
1554 if (c == '\n' || curs <= 0)
1556 edit_insert (edit, '\n');
1557 return;
1559 if (c == ' ' || c == '\t')
1561 int current = edit->curs1;
1562 edit_cursor_move (edit, curs - edit->curs1 + 1);
1563 edit_insert (edit, '\n');
1564 edit_cursor_move (edit, current - edit->curs1 + 1);
1565 return;
1570 /* --------------------------------------------------------------------------------------------- */
1571 /** this find the matching bracket in either direction, and sets edit->bracket */
1573 static long
1574 edit_get_bracket (WEdit * edit, int in_screen, unsigned long furthest_bracket_search)
1576 const char *const b = "{}{[][()(", *p;
1577 int i = 1, a, inc = -1, c, d, n = 0;
1578 unsigned long j = 0;
1579 long q;
1580 edit_update_curs_row (edit);
1581 c = edit_get_byte (edit, edit->curs1);
1582 p = strchr (b, c);
1583 /* no limit */
1584 if (!furthest_bracket_search)
1585 furthest_bracket_search--;
1586 /* not on a bracket at all */
1587 if (!p)
1588 return -1;
1589 /* the matching bracket */
1590 d = p[1];
1591 /* going left or right? */
1592 if (strchr ("{[(", c))
1593 inc = 1;
1594 for (q = edit->curs1 + inc;; q += inc)
1596 /* out of buffer? */
1597 if (q >= edit->last_byte || q < 0)
1598 break;
1599 a = edit_get_byte (edit, q);
1600 /* don't want to eat CPU */
1601 if (j++ > furthest_bracket_search)
1602 break;
1603 /* out of screen? */
1604 if (in_screen)
1606 if (q < edit->start_display)
1607 break;
1608 /* count lines if searching downward */
1609 if (inc > 0 && a == '\n')
1610 if (n++ >= edit->widget.lines - edit->curs_row) /* out of screen */
1611 break;
1613 /* count bracket depth */
1614 i += (a == c) - (a == d);
1615 /* return if bracket depth is zero */
1616 if (!i)
1617 return q;
1619 /* no match */
1620 return -1;
1623 /* --------------------------------------------------------------------------------------------- */
1625 static inline void
1626 edit_goto_matching_bracket (WEdit * edit)
1628 long q;
1630 q = edit_get_bracket (edit, 0, 0);
1631 if (q >= 0)
1633 edit->bracket = edit->curs1;
1634 edit->force |= REDRAW_PAGE;
1635 edit_cursor_move (edit, q - edit->curs1);
1639 /* --------------------------------------------------------------------------------------------- */
1640 /*** public functions ****************************************************************************/
1641 /* --------------------------------------------------------------------------------------------- */
1643 /** User edit menu, like user menu (F2) but only in editor. */
1645 void
1646 user_menu (WEdit * edit, const char *menu_file, int selected_entry)
1648 char *block_file;
1649 int nomark;
1650 long curs;
1651 long start_mark, end_mark;
1652 struct stat status;
1654 block_file = concat_dir_and_file (mc_config_get_cache_path (), EDIT_BLOCK_FILE);
1655 curs = edit->curs1;
1656 nomark = eval_marks (edit, &start_mark, &end_mark);
1657 if (nomark == 0)
1658 edit_save_block (edit, block_file, start_mark, end_mark);
1660 /* run shell scripts from menu */
1661 if (user_menu_cmd (edit, menu_file, selected_entry)
1662 && (mc_stat (block_file, &status) == 0) && (status.st_size != 0))
1664 int rc = 0;
1665 FILE *fd;
1667 /* i.e. we have marked block */
1668 if (nomark == 0)
1669 rc = edit_block_delete_cmd (edit);
1671 if (rc == 0)
1673 long ins_len;
1675 ins_len = edit_insert_file (edit, block_file);
1676 if (nomark == 0 && ins_len > 0)
1677 edit_set_markers (edit, start_mark, start_mark + ins_len, 0, 0);
1679 /* truncate block file */
1680 fd = fopen (block_file, "w");
1681 if (fd != NULL)
1682 fclose (fd);
1684 edit_cursor_move (edit, curs - edit->curs1);
1685 edit_refresh_cmd (edit);
1686 edit->force |= REDRAW_COMPLETELY;
1688 g_free (block_file);
1691 /* --------------------------------------------------------------------------------------------- */
1694 edit_get_byte (WEdit * edit, long byte_index)
1696 unsigned long p;
1697 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
1698 return '\n';
1700 if (byte_index >= edit->curs1)
1702 p = edit->curs1 + edit->curs2 - byte_index - 1;
1703 return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1];
1705 else
1707 return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE];
1711 /* --------------------------------------------------------------------------------------------- */
1713 char *
1714 edit_get_byte_ptr (WEdit * edit, long byte_index)
1716 unsigned long p;
1717 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
1718 return NULL;
1720 if (byte_index >= edit->curs1)
1722 p = edit->curs1 + edit->curs2 - byte_index - 1;
1723 return (char *) (edit->buffers2[p >> S_EDIT_BUF_SIZE] +
1724 (EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1));
1726 else
1728 return (char *) (edit->buffers1[byte_index >> S_EDIT_BUF_SIZE] +
1729 (byte_index & M_EDIT_BUF_SIZE));
1733 /* --------------------------------------------------------------------------------------------- */
1735 char *
1736 edit_get_buf_ptr (WEdit * edit, long byte_index)
1738 unsigned long p;
1740 if (byte_index >= (edit->curs1 + edit->curs2))
1741 byte_index--;
1743 if (byte_index < 0)
1744 return NULL;
1746 if (byte_index >= edit->curs1)
1748 p = edit->curs1 + edit->curs2 - 1;
1749 return (char *) (edit->buffers2[p >> S_EDIT_BUF_SIZE] +
1750 (EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1));
1752 else
1754 return (char *) (edit->buffers1[byte_index >> S_EDIT_BUF_SIZE] + (0 & M_EDIT_BUF_SIZE));
1758 /* --------------------------------------------------------------------------------------------- */
1761 edit_get_utf (WEdit * edit, long byte_index, int *char_width)
1763 gchar *str = NULL;
1764 int res = -1;
1765 gunichar ch;
1766 gchar *next_ch = NULL;
1767 int width = 0;
1769 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
1771 *char_width = 0;
1772 return '\n';
1775 str = edit_get_byte_ptr (edit, byte_index);
1777 if (str == NULL)
1779 *char_width = 0;
1780 return 0;
1783 res = g_utf8_get_char_validated (str, -1);
1785 if (res < 0)
1787 ch = *str;
1788 width = 0;
1790 else
1792 ch = res;
1793 /* Calculate UTF-8 char width */
1794 next_ch = g_utf8_next_char (str);
1795 if (next_ch)
1797 width = next_ch - str;
1799 else
1801 ch = 0;
1802 width = 0;
1805 *char_width = width;
1806 return ch;
1809 /* --------------------------------------------------------------------------------------------- */
1812 edit_get_prev_utf (WEdit * edit, long byte_index, int *char_width)
1814 gchar *str, *buf = NULL;
1815 int res = -1;
1816 gunichar ch;
1817 gchar *next_ch = NULL;
1818 int width = 0;
1820 if (byte_index > 0)
1821 byte_index--;
1823 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
1825 *char_width = 0;
1826 return 0;
1829 ch = edit_get_utf (edit, byte_index, &width);
1831 if (width == 1)
1833 *char_width = width;
1834 return ch;
1837 str = edit_get_byte_ptr (edit, byte_index);
1838 buf = edit_get_buf_ptr (edit, byte_index);
1839 if (str == NULL || buf == NULL)
1841 *char_width = 0;
1842 return 0;
1844 /* get prev utf8 char */
1845 if (str != buf)
1846 str = g_utf8_find_prev_char (buf, str);
1848 if (str == NULL)
1850 *char_width = 0;
1851 return 0;
1853 else
1854 res = g_utf8_get_char_validated (str, -1);
1856 if (res < 0)
1858 ch = *str;
1859 width = 0;
1861 else
1863 ch = res;
1864 /* Calculate UTF-8 char width */
1865 next_ch = g_utf8_next_char (str);
1866 if (next_ch)
1868 width = next_ch - str;
1870 else
1872 ch = 0;
1873 width = 0;
1876 *char_width = width;
1877 return ch;
1880 /* --------------------------------------------------------------------------------------------- */
1882 char *
1883 edit_get_write_filter (const char *write_name, const char *filename)
1885 int i;
1886 char *p, *writename;
1888 i = edit_find_filter (filename);
1889 if (i < 0)
1890 return NULL;
1892 writename = name_quote (write_name, 0);
1893 p = g_strdup_printf (all_filters[i].write, writename);
1894 g_free (writename);
1895 return p;
1898 /* --------------------------------------------------------------------------------------------- */
1900 long
1901 edit_write_stream (WEdit * edit, FILE * f)
1903 long i;
1905 if (edit->lb == LB_ASIS)
1907 for (i = 0; i < edit->last_byte; i++)
1908 if (fputc (edit_get_byte (edit, i), f) < 0)
1909 break;
1910 return i;
1913 /* change line breaks */
1914 for (i = 0; i < edit->last_byte; i++)
1916 unsigned char c = edit_get_byte (edit, i);
1918 if (!(c == '\n' || c == '\r'))
1920 /* not line break */
1921 if (fputc (c, f) < 0)
1922 return i;
1924 else
1925 { /* (c == '\n' || c == '\r') */
1926 unsigned char c1 = edit_get_byte (edit, i + 1); /* next char */
1928 switch (edit->lb)
1930 case LB_UNIX: /* replace "\r\n" or '\r' to '\n' */
1931 /* put one line break unconditionally */
1932 if (fputc ('\n', f) < 0)
1933 return i;
1935 i++; /* 2 chars are processed */
1937 if (c == '\r' && c1 == '\n')
1938 /* Windows line break; go to the next char */
1939 break;
1941 if (c == '\r' && c1 == '\r')
1943 /* two Macintosh line breaks; put second line break */
1944 if (fputc ('\n', f) < 0)
1945 return i;
1946 break;
1949 if (fputc (c1, f) < 0)
1950 return i;
1951 break;
1953 case LB_WIN: /* replace '\n' or '\r' to "\r\n" */
1954 /* put one line break unconditionally */
1955 if (fputc ('\r', f) < 0 || fputc ('\n', f) < 0)
1956 return i;
1958 if (c == '\r' && c1 == '\n')
1959 /* Windows line break; go to the next char */
1960 i++;
1961 break;
1963 case LB_MAC: /* replace "\r\n" or '\n' to '\r' */
1964 /* put one line break unconditionally */
1965 if (fputc ('\r', f) < 0)
1966 return i;
1968 i++; /* 2 chars are processed */
1970 if (c == '\r' && c1 == '\n')
1971 /* Windows line break; go to the next char */
1972 break;
1974 if (c == '\n' && c1 == '\n')
1976 /* two Windows line breaks; put second line break */
1977 if (fputc ('\r', f) < 0)
1978 return i;
1979 break;
1982 if (fputc (c1, f) < 0)
1983 return i;
1984 break;
1985 case LB_ASIS: /* default without changes */
1986 break;
1991 return edit->last_byte;
1994 /* --------------------------------------------------------------------------------------------- */
1995 /** inserts a file at the cursor, returns count of inserted bytes on success */
1996 long
1997 edit_insert_file (WEdit * edit, const char *filename)
1999 char *p;
2000 long ins_len = 0;
2002 p = edit_get_filter (filename);
2003 if (p != NULL)
2005 FILE *f;
2006 long current = edit->curs1;
2007 f = (FILE *) popen (p, "r");
2008 if (f != NULL)
2010 edit_insert_stream (edit, f);
2011 ins_len = edit->curs1 - current;
2012 edit_cursor_move (edit, current - edit->curs1);
2013 if (pclose (f) > 0)
2015 char *errmsg;
2016 errmsg = g_strdup_printf (_("Error reading from pipe: %s"), p);
2017 edit_error_dialog (_("Error"), errmsg);
2018 g_free (errmsg);
2019 g_free (p);
2020 return 0;
2023 else
2025 char *errmsg;
2026 errmsg = g_strdup_printf (_("Cannot open pipe for reading: %s"), p);
2027 edit_error_dialog (_("Error"), errmsg);
2028 g_free (errmsg);
2029 g_free (p);
2030 return 0;
2032 g_free (p);
2034 else
2036 int i, file, blocklen;
2037 long current = edit->curs1;
2038 int vertical_insertion = 0;
2039 char *buf;
2040 file = mc_open (filename, O_RDONLY | O_BINARY);
2041 if (file == -1)
2042 return 0;
2043 buf = g_malloc0 (TEMP_BUF_LEN);
2044 blocklen = mc_read (file, buf, sizeof (VERTICAL_MAGIC));
2045 if (blocklen > 0)
2047 /* if contain signature VERTICAL_MAGIC then it vertical block */
2048 if (memcmp (buf, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC)) == 0)
2049 vertical_insertion = 1;
2050 else
2051 mc_lseek (file, 0, SEEK_SET);
2053 if (vertical_insertion)
2055 long mark1, mark2;
2056 int c1, c2;
2057 blocklen = edit_insert_column_of_text_from_file (edit, file, &mark1, &mark2, &c1, &c2);
2058 edit_set_markers (edit, edit->curs1, mark2, c1, c2);
2059 /* highlight inserted text then not persistent blocks */
2060 if (!option_persistent_selections)
2062 if (!edit->column_highlight)
2063 edit_push_undo_action (edit, COLUMN_OFF);
2064 edit->column_highlight = 1;
2067 else
2069 while ((blocklen = mc_read (file, (char *) buf, TEMP_BUF_LEN)) > 0)
2071 for (i = 0; i < blocklen; i++)
2072 edit_insert (edit, buf[i]);
2074 /* highlight inserted text then not persistent blocks */
2075 if (!option_persistent_selections)
2077 edit_set_markers (edit, edit->curs1, current, 0, 0);
2078 if (edit->column_highlight)
2079 edit_push_undo_action (edit, COLUMN_ON);
2080 edit->column_highlight = 0;
2083 edit->force |= REDRAW_PAGE;
2084 ins_len = edit->curs1 - current;
2085 edit_cursor_move (edit, current - edit->curs1);
2086 g_free (buf);
2087 mc_close (file);
2088 if (blocklen != 0)
2089 return 0;
2091 return ins_len;
2094 /* --------------------------------------------------------------------------------------------- */
2096 * Fill in the edit structure. Return NULL on failure. Pass edit as
2097 * NULL to allocate a new structure.
2099 * If line is 0, try to restore saved position. Otherwise put the
2100 * cursor on that line and show it in the middle of the screen.
2103 WEdit *
2104 edit_init (WEdit * edit, int lines, int columns, const char *filename, long line)
2106 int to_free = 0;
2107 option_auto_syntax = 1; /* Resetting to auto on every invokation */
2108 if (option_line_state)
2110 option_line_state_width = LINE_STATE_WIDTH;
2112 else
2114 option_line_state_width = 0;
2116 if (!edit)
2118 #ifdef ENABLE_NLS
2120 * Expand option_whole_chars_search by national letters using
2121 * current locale
2124 static char option_whole_chars_search_buf[256];
2126 if (option_whole_chars_search_buf != option_whole_chars_search)
2128 size_t i;
2129 size_t len = str_term_width1 (option_whole_chars_search);
2131 strcpy (option_whole_chars_search_buf, option_whole_chars_search);
2133 for (i = 1; i <= sizeof (option_whole_chars_search_buf); i++)
2135 if (g_ascii_islower ((gchar) i) && !strchr (option_whole_chars_search, i))
2137 option_whole_chars_search_buf[len++] = i;
2141 option_whole_chars_search_buf[len] = 0;
2142 option_whole_chars_search = option_whole_chars_search_buf;
2144 #endif /* ENABLE_NLS */
2145 edit = g_malloc0 (sizeof (WEdit));
2146 edit->search = NULL;
2147 to_free = 1;
2149 edit_purge_widget (edit);
2150 edit->widget.lines = lines;
2151 edit->over_col = 0;
2152 edit->widget.cols = columns;
2153 edit->stat1.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
2154 edit->stat1.st_uid = getuid ();
2155 edit->stat1.st_gid = getgid ();
2156 edit->stat1.st_mtime = 0;
2157 edit->bracket = -1;
2158 edit->force |= REDRAW_PAGE;
2159 edit_set_filename (edit, filename);
2160 edit->undo_stack_size = START_STACK_SIZE;
2161 edit->undo_stack_size_mask = START_STACK_SIZE - 1;
2162 edit->undo_stack = g_malloc0 ((edit->undo_stack_size + 10) * sizeof (long));
2164 edit->redo_stack_size = START_STACK_SIZE;
2165 edit->redo_stack_size_mask = START_STACK_SIZE - 1;
2166 edit->redo_stack = g_malloc0 ((edit->redo_stack_size + 10) * sizeof (long));
2168 edit->utf8 = 0;
2169 edit->converter = str_cnv_from_term;
2170 edit_set_codeset (edit);
2172 if (edit_load_file (edit))
2174 /* edit_load_file already gives an error message */
2175 if (to_free)
2176 g_free (edit);
2177 return 0;
2180 edit->loading_done = 1;
2181 edit->modified = 0;
2182 edit->locked = 0;
2183 edit_load_syntax (edit, NULL, NULL);
2185 int color;
2186 edit_get_syntax_color (edit, -1, &color);
2189 /* load saved cursor position */
2190 if ((line == 0) && option_save_position)
2192 edit_load_position (edit);
2194 else
2196 if (line <= 0)
2197 line = 1;
2198 edit_move_display (edit, line - 1);
2199 edit_move_to_line (edit, line - 1);
2202 edit_load_macro_cmd (edit);
2203 return edit;
2206 /* --------------------------------------------------------------------------------------------- */
2207 /** Clear the edit struct, freeing everything in it. Return 1 on success */
2210 edit_clean (WEdit * edit)
2212 int j = 0;
2214 if (!edit)
2215 return 0;
2217 /* a stale lock, remove it */
2218 if (edit->locked)
2219 edit->locked = edit_unlock_file (edit);
2221 /* save cursor position */
2222 if (option_save_position)
2223 edit_save_position (edit);
2224 else if (edit->serialized_bookmarks != NULL)
2225 edit->serialized_bookmarks = (GArray *) g_array_free (edit->serialized_bookmarks, TRUE);
2227 /* File specified on the mcedit command line and never saved */
2228 if (edit->delete_file)
2229 unlink (edit->filename);
2231 edit_free_syntax_rules (edit);
2232 book_mark_flush (edit, -1);
2233 for (; j <= MAXBUFF; j++)
2235 g_free (edit->buffers1[j]);
2236 g_free (edit->buffers2[j]);
2239 g_free (edit->undo_stack);
2240 g_free (edit->redo_stack);
2241 g_free (edit->filename);
2242 g_free (edit->dir);
2243 mc_search_free (edit->search);
2244 edit->search = NULL;
2246 if (edit->converter != str_cnv_from_term)
2247 str_close_conv (edit->converter);
2249 edit_purge_widget (edit);
2251 return 1;
2254 /* --------------------------------------------------------------------------------------------- */
2255 /** returns 1 on success */
2258 edit_renew (WEdit * edit)
2260 int lines = edit->widget.lines;
2261 int columns = edit->widget.cols;
2263 edit_clean (edit);
2264 return (edit_init (edit, lines, columns, "", 0) != NULL);
2267 /* --------------------------------------------------------------------------------------------- */
2269 * Load a new file into the editor. If it fails, preserve the old file.
2270 * To do it, allocate a new widget, initialize it and, if the new file
2271 * was loaded, copy the data to the old widget.
2272 * Return 1 on success, 0 on failure.
2276 edit_reload (WEdit * edit, const char *filename)
2278 WEdit *e;
2279 int lines = edit->widget.lines;
2280 int columns = edit->widget.cols;
2282 e = g_malloc0 (sizeof (WEdit));
2283 e->widget = edit->widget;
2284 if (!edit_init (e, lines, columns, filename, 0))
2286 g_free (e);
2287 return 0;
2289 edit_clean (edit);
2290 memcpy (edit, e, sizeof (WEdit));
2291 g_free (e);
2292 return 1;
2295 /* --------------------------------------------------------------------------------------------- */
2297 * Load a new file into the editor and set line. If it fails, preserve the old file.
2298 * To do it, allocate a new widget, initialize it and, if the new file
2299 * was loaded, copy the data to the old widget.
2300 * Return 1 on success, 0 on failure.
2304 edit_reload_line (WEdit * edit, const char *filename, long line)
2306 WEdit *e;
2307 int lines = edit->widget.lines;
2308 int columns = edit->widget.cols;
2310 e = g_malloc0 (sizeof (WEdit));
2311 e->widget = edit->widget;
2312 if (!edit_init (e, lines, columns, filename, line))
2314 g_free (e);
2315 return 0;
2317 edit_clean (edit);
2318 memcpy (edit, e, sizeof (WEdit));
2319 g_free (e);
2320 return 1;
2323 /* --------------------------------------------------------------------------------------------- */
2325 void
2326 edit_set_codeset (WEdit * edit)
2328 #ifdef HAVE_CHARSET
2329 const char *cp_id;
2331 cp_id =
2332 get_codepage_id (mc_global.source_codepage >=
2333 0 ? mc_global.source_codepage : mc_global.display_codepage);
2335 if (cp_id != NULL)
2337 GIConv conv;
2338 conv = str_crt_conv_from (cp_id);
2339 if (conv != INVALID_CONV)
2341 if (edit->converter != str_cnv_from_term)
2342 str_close_conv (edit->converter);
2343 edit->converter = conv;
2347 if (cp_id != NULL)
2348 edit->utf8 = str_isutf8 (cp_id);
2349 #else
2350 (void) edit;
2351 #endif
2355 /* --------------------------------------------------------------------------------------------- */
2357 Recording stack for undo:
2358 The following is an implementation of a compressed stack. Identical
2359 pushes are recorded by a negative prefix indicating the number of times the
2360 same char was pushed. This saves space for repeated curs-left or curs-right
2361 delete etc.
2365 pushed: stored:
2369 b -3
2371 c --> -4
2377 If the stack long int is 0-255 it represents a normal insert (from a backspace),
2378 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
2379 of the cursor functions #define'd in edit-impl.h. 1000 through 700'000'000 is to
2380 set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
2381 position.
2383 The only way the cursor moves or the buffer is changed is through the routines:
2384 insert, backspace, insert_ahead, delete, and cursor_move.
2385 These record the reverse undo movements onto the stack each time they are
2386 called.
2388 Each key press results in a set of actions (insert; delete ...). So each time
2389 a key is pressed the current position of start_display is pushed as
2390 KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
2391 over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
2392 tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
2396 void
2397 edit_push_undo_action (WEdit * edit, long c, ...)
2399 unsigned long sp = edit->undo_stack_pointer;
2400 unsigned long spm1;
2401 long *t;
2403 /* first enlarge the stack if necessary */
2404 if (sp > edit->undo_stack_size - 10)
2405 { /* say */
2406 if (option_max_undo < 256)
2407 option_max_undo = 256;
2408 if (edit->undo_stack_size < (unsigned long) option_max_undo)
2410 t = g_realloc (edit->undo_stack, (edit->undo_stack_size * 2 + 10) * sizeof (long));
2411 if (t)
2413 edit->undo_stack = t;
2414 edit->undo_stack_size <<= 1;
2415 edit->undo_stack_size_mask = edit->undo_stack_size - 1;
2419 spm1 = (edit->undo_stack_pointer - 1) & edit->undo_stack_size_mask;
2420 if (edit->undo_stack_disable)
2422 edit_push_redo_action (edit, KEY_PRESS);
2423 edit_push_redo_action (edit, c);
2424 return;
2426 else if (edit->redo_stack_reset)
2428 edit->redo_stack_bottom = edit->redo_stack_pointer = 0;
2431 if (edit->undo_stack_bottom != sp
2432 && spm1 != edit->undo_stack_bottom
2433 && ((sp - 2) & edit->undo_stack_size_mask) != edit->undo_stack_bottom)
2435 int d;
2436 if (edit->undo_stack[spm1] < 0)
2438 d = edit->undo_stack[(sp - 2) & edit->undo_stack_size_mask];
2439 if (d == c)
2441 if (edit->undo_stack[spm1] > -1000000000)
2443 if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
2445 edit->undo_stack[spm1]--;
2447 return;
2451 else
2453 d = edit->undo_stack[spm1];
2454 if (d == c)
2456 if (c >= KEY_PRESS)
2457 return; /* --> no need to push multiple do-nothings */
2458 edit->undo_stack[sp] = -2;
2459 goto check_bottom;
2463 edit->undo_stack[sp] = c;
2465 check_bottom:
2466 edit->undo_stack_pointer = (edit->undo_stack_pointer + 1) & edit->undo_stack_size_mask;
2468 /* if the sp wraps round and catches the undo_stack_bottom then erase
2469 * the first set of actions on the stack to make space - by moving
2470 * undo_stack_bottom forward one "key press" */
2471 c = (edit->undo_stack_pointer + 2) & edit->undo_stack_size_mask;
2472 if ((unsigned long) c == edit->undo_stack_bottom ||
2473 (((unsigned long) c + 1) & edit->undo_stack_size_mask) == edit->undo_stack_bottom)
2476 edit->undo_stack_bottom = (edit->undo_stack_bottom + 1) & edit->undo_stack_size_mask;
2478 while (edit->undo_stack[edit->undo_stack_bottom] < KEY_PRESS
2479 && edit->undo_stack_bottom != edit->undo_stack_pointer);
2481 /*If a single key produced enough pushes to wrap all the way round then we would notice that the [undo_stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */
2482 if (edit->undo_stack_pointer != edit->undo_stack_bottom
2483 && edit->undo_stack[edit->undo_stack_bottom] < KEY_PRESS)
2485 edit->undo_stack_bottom = edit->undo_stack_pointer = 0;
2489 void
2490 edit_push_redo_action (WEdit * edit, long c, ...)
2492 unsigned long sp = edit->redo_stack_pointer;
2493 unsigned long spm1;
2494 long *t;
2495 /* first enlarge the stack if necessary */
2496 if (sp > edit->redo_stack_size - 10)
2497 { /* say */
2498 if (option_max_undo < 256)
2499 option_max_undo = 256;
2500 if (edit->redo_stack_size < (unsigned long) option_max_undo)
2502 t = g_realloc (edit->redo_stack, (edit->redo_stack_size * 2 + 10) * sizeof (long));
2503 if (t)
2505 edit->redo_stack = t;
2506 edit->redo_stack_size <<= 1;
2507 edit->redo_stack_size_mask = edit->redo_stack_size - 1;
2511 spm1 = (edit->redo_stack_pointer - 1) & edit->redo_stack_size_mask;
2513 if (edit->redo_stack_bottom != sp
2514 && spm1 != edit->redo_stack_bottom
2515 && ((sp - 2) & edit->redo_stack_size_mask) != edit->redo_stack_bottom)
2517 int d;
2518 if (edit->redo_stack[spm1] < 0)
2520 d = edit->redo_stack[(sp - 2) & edit->redo_stack_size_mask];
2521 if (d == c)
2523 if (edit->redo_stack[spm1] > -1000000000)
2525 if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
2526 edit->redo_stack[spm1]--;
2527 return;
2531 else
2533 d = edit->redo_stack[spm1];
2534 if (d == c)
2536 if (c >= KEY_PRESS)
2537 return; /* --> no need to push multiple do-nothings */
2538 edit->redo_stack[sp] = -2;
2539 goto redo_check_bottom;
2543 edit->redo_stack[sp] = c;
2545 redo_check_bottom:
2546 edit->redo_stack_pointer = (edit->redo_stack_pointer + 1) & edit->redo_stack_size_mask;
2548 /* if the sp wraps round and catches the redo_stack_bottom then erase
2549 * the first set of actions on the stack to make space - by moving
2550 * redo_stack_bottom forward one "key press" */
2551 c = (edit->redo_stack_pointer + 2) & edit->redo_stack_size_mask;
2552 if ((unsigned long) c == edit->redo_stack_bottom ||
2553 (((unsigned long) c + 1) & edit->redo_stack_size_mask) == edit->redo_stack_bottom)
2556 edit->redo_stack_bottom = (edit->redo_stack_bottom + 1) & edit->redo_stack_size_mask;
2558 while (edit->redo_stack[edit->redo_stack_bottom] < KEY_PRESS
2559 && edit->redo_stack_bottom != edit->redo_stack_pointer);
2562 * If a single key produced enough pushes to wrap all the way round then
2563 * we would notice that the [redo_stack_bottom] does not contain KEY_PRESS.
2564 * The stack is then initialised:
2567 if (edit->redo_stack_pointer != edit->redo_stack_bottom
2568 && edit->redo_stack[edit->redo_stack_bottom] < KEY_PRESS)
2569 edit->redo_stack_bottom = edit->redo_stack_pointer = 0;
2573 /* --------------------------------------------------------------------------------------------- */
2575 Basic low level single character buffer alterations and movements at the cursor.
2576 Returns char passed over, inserted or removed.
2579 void
2580 edit_insert (WEdit * edit, int c)
2582 /* check if file has grown to large */
2583 if (edit->last_byte >= SIZE_LIMIT)
2584 return;
2586 /* first we must update the position of the display window */
2587 if (edit->curs1 < edit->start_display)
2589 edit->start_display++;
2590 if (c == '\n')
2591 edit->start_line++;
2594 /* Mark file as modified, unless the file hasn't been fully loaded */
2595 if (edit->loading_done)
2597 edit_modification (edit);
2600 /* now we must update some info on the file and check if a redraw is required */
2601 if (c == '\n')
2603 if (edit->book_mark)
2604 book_mark_inc (edit, edit->curs_line);
2605 edit->curs_line++;
2606 edit->total_lines++;
2607 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
2610 /* save the reverse command onto the undo stack */
2611 /* ordinary char and not space */
2612 if (c > 32)
2613 edit_push_undo_action (edit, BACKSPACE);
2614 else
2615 edit_push_undo_action (edit, BACKSPACE_BR);
2616 /* update markers */
2617 edit->mark1 += (edit->mark1 > edit->curs1);
2618 edit->mark2 += (edit->mark2 > edit->curs1);
2619 edit->last_get_rule += (edit->last_get_rule > edit->curs1);
2621 /* add a new buffer if we've reached the end of the last one */
2622 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
2623 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
2625 /* perform the insertion */
2626 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE]
2627 = (unsigned char) c;
2629 /* update file length */
2630 edit->last_byte++;
2632 /* update cursor position */
2633 edit->curs1++;
2636 /* --------------------------------------------------------------------------------------------- */
2637 /** same as edit_insert and move left */
2639 void
2640 edit_insert_ahead (WEdit * edit, int c)
2642 if (edit->last_byte >= SIZE_LIMIT)
2643 return;
2645 if (edit->curs1 < edit->start_display)
2647 edit->start_display++;
2648 if (c == '\n')
2649 edit->start_line++;
2651 edit_modification (edit);
2652 if (c == '\n')
2654 if (edit->book_mark)
2655 book_mark_inc (edit, edit->curs_line);
2656 edit->total_lines++;
2657 edit->force |= REDRAW_AFTER_CURSOR;
2659 /* ordinary char and not space */
2660 if (c > 32)
2661 edit_push_undo_action (edit, DELCHAR);
2662 else
2663 edit_push_undo_action (edit, DELCHAR_BR);
2665 edit->mark1 += (edit->mark1 >= edit->curs1);
2666 edit->mark2 += (edit->mark2 >= edit->curs1);
2667 edit->last_get_rule += (edit->last_get_rule >= edit->curs1);
2669 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
2670 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
2671 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]
2672 [EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
2674 edit->last_byte++;
2675 edit->curs2++;
2679 /* --------------------------------------------------------------------------------------------- */
2682 edit_delete (WEdit * edit, const int byte_delete)
2684 int p = 0;
2685 int cw = 1;
2686 int i;
2688 if (!edit->curs2)
2689 return 0;
2691 cw = 1;
2692 /* if byte_delete = 1 then delete only one byte not multibyte char */
2693 if (edit->utf8 && byte_delete == 0)
2695 edit_get_utf (edit, edit->curs1, &cw);
2696 if (cw < 1)
2697 cw = 1;
2700 if (edit->mark2 != edit->mark1)
2701 edit_push_markers (edit);
2703 for (i = 1; i <= cw; i++)
2705 if (edit->mark1 > edit->curs1)
2707 edit->mark1--;
2708 edit->end_mark_curs--;
2710 if (edit->mark2 > edit->curs1)
2711 edit->mark2--;
2712 if (edit->last_get_rule > edit->curs1)
2713 edit->last_get_rule--;
2715 p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE -
2716 ((edit->curs2 -
2717 1) & M_EDIT_BUF_SIZE) - 1];
2719 if (!(edit->curs2 & M_EDIT_BUF_SIZE))
2721 g_free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
2722 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL;
2724 edit->last_byte--;
2725 edit->curs2--;
2726 edit_push_undo_action (edit, p + 256);
2729 edit_modification (edit);
2730 if (p == '\n')
2732 if (edit->book_mark)
2733 book_mark_dec (edit, edit->curs_line);
2734 edit->total_lines--;
2735 edit->force |= REDRAW_AFTER_CURSOR;
2737 if (edit->curs1 < edit->start_display)
2739 edit->start_display--;
2740 if (p == '\n')
2741 edit->start_line--;
2744 return p;
2747 /* --------------------------------------------------------------------------------------------- */
2748 /** moves the cursor right or left: increment positive or negative respectively */
2750 void
2751 edit_cursor_move (WEdit * edit, long increment)
2753 /* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
2754 int c;
2756 if (increment < 0)
2758 for (; increment < 0; increment++)
2760 if (!edit->curs1)
2761 return;
2763 edit_push_undo_action (edit, CURS_RIGHT);
2765 c = edit_get_byte (edit, edit->curs1 - 1);
2766 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
2767 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
2768 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE -
2769 (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
2770 edit->curs2++;
2771 c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 -
2772 1) & M_EDIT_BUF_SIZE];
2773 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE))
2775 g_free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
2776 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
2778 edit->curs1--;
2779 if (c == '\n')
2781 edit->curs_line--;
2782 edit->force |= REDRAW_LINE_BELOW;
2787 else if (increment > 0)
2789 for (; increment > 0; increment--)
2791 if (!edit->curs2)
2792 return;
2794 edit_push_undo_action (edit, CURS_LEFT);
2796 c = edit_get_byte (edit, edit->curs1);
2797 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
2798 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
2799 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c;
2800 edit->curs1++;
2801 c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE -
2802 ((edit->curs2 -
2803 1) & M_EDIT_BUF_SIZE) - 1];
2804 if (!(edit->curs2 & M_EDIT_BUF_SIZE))
2806 g_free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
2807 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = 0;
2809 edit->curs2--;
2810 if (c == '\n')
2812 edit->curs_line++;
2813 edit->force |= REDRAW_LINE_ABOVE;
2819 /* These functions return positions relative to lines */
2821 /* --------------------------------------------------------------------------------------------- */
2822 /** returns index of last char on line + 1 */
2824 long
2825 edit_eol (WEdit * edit, long current)
2827 if (current >= edit->last_byte)
2828 return edit->last_byte;
2830 for (;; current++)
2831 if (edit_get_byte (edit, current) == '\n')
2832 break;
2833 return current;
2836 /* --------------------------------------------------------------------------------------------- */
2837 /** returns index of first char on line */
2839 long
2840 edit_bol (WEdit * edit, long current)
2842 if (current <= 0)
2843 return 0;
2845 for (;; current--)
2846 if (edit_get_byte (edit, current - 1) == '\n')
2847 break;
2848 return current;
2851 /* --------------------------------------------------------------------------------------------- */
2853 long
2854 edit_count_lines (WEdit * edit, long current, long upto)
2856 long lines = 0;
2857 if (upto > edit->last_byte)
2858 upto = edit->last_byte;
2859 if (current < 0)
2860 current = 0;
2861 while (current < upto)
2862 if (edit_get_byte (edit, current++) == '\n')
2863 lines++;
2864 return lines;
2867 /* --------------------------------------------------------------------------------------------- */
2868 /* If lines is zero this returns the count of lines from current to upto. */
2869 /* If upto is zero returns index of lines forward current. */
2871 long
2872 edit_move_forward (WEdit * edit, long current, long lines, long upto)
2874 if (upto)
2876 return edit_count_lines (edit, current, upto);
2878 else
2880 long next;
2881 if (lines < 0)
2882 lines = 0;
2883 while (lines--)
2885 next = edit_eol (edit, current) + 1;
2886 if (next > edit->last_byte)
2887 break;
2888 else
2889 current = next;
2891 return current;
2895 /* --------------------------------------------------------------------------------------------- */
2896 /** Returns offset of 'lines' lines up from current */
2898 long
2899 edit_move_backward (WEdit * edit, long current, long lines)
2901 if (lines < 0)
2902 lines = 0;
2903 current = edit_bol (edit, current);
2904 while ((lines--) && current != 0)
2905 current = edit_bol (edit, current - 1);
2906 return current;
2909 /* --------------------------------------------------------------------------------------------- */
2910 /* If cols is zero this returns the count of columns from current to upto. */
2911 /* If upto is zero returns index of cols across from current. */
2913 long
2914 edit_move_forward3 (WEdit * edit, long current, int cols, long upto)
2916 long p, q;
2917 int col;
2919 if (upto)
2921 q = upto;
2922 cols = -10;
2924 else
2925 q = edit->last_byte + 2;
2927 for (col = 0, p = current; p < q; p++)
2929 int c, orig_c;
2931 if (cols != -10)
2933 if (col == cols)
2934 return p;
2935 if (col > cols)
2936 return p - 1;
2939 orig_c = c = edit_get_byte (edit, p);
2941 #ifdef HAVE_CHARSET
2942 if (edit->utf8)
2944 int utf_ch;
2945 int cw = 1;
2947 utf_ch = edit_get_utf (edit, p, &cw);
2948 if (mc_global.utf8_display)
2950 if (cw > 1)
2951 col -= cw - 1;
2952 if (g_unichar_iswide (utf_ch))
2953 col++;
2955 else if (cw > 1 && g_unichar_isprint (utf_ch))
2956 col -= cw - 1;
2959 c = convert_to_display_c (c);
2960 #endif
2962 if (c == '\t')
2963 col += TAB_SIZE - col % TAB_SIZE;
2964 else if (c == '\n')
2966 if (upto)
2967 return col;
2968 else
2969 return p;
2971 else if ((c < 32 || c == 127) && (orig_c == c || (!mc_global.utf8_display && !edit->utf8)))
2972 /* '\r' is shown as ^M, so we must advance 2 characters */
2973 /* Caret notation for control characters */
2974 col += 2;
2975 else
2976 col++;
2978 return col;
2981 /* --------------------------------------------------------------------------------------------- */
2982 /** returns the current column position of the cursor */
2985 edit_get_col (WEdit * edit)
2987 return edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
2990 /* --------------------------------------------------------------------------------------------- */
2991 /* Scrolling functions */
2992 /* --------------------------------------------------------------------------------------------- */
2994 void
2995 edit_update_curs_row (WEdit * edit)
2997 edit->curs_row = edit->curs_line - edit->start_line;
3000 /* --------------------------------------------------------------------------------------------- */
3002 void
3003 edit_update_curs_col (WEdit * edit)
3005 edit->curs_col = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
3008 /* --------------------------------------------------------------------------------------------- */
3011 edit_get_curs_col (const WEdit * edit)
3013 return edit->curs_col;
3016 /* --------------------------------------------------------------------------------------------- */
3017 /** moves the display start position up by i lines */
3019 void
3020 edit_scroll_upward (WEdit * edit, unsigned long i)
3022 unsigned long lines_above = edit->start_line;
3023 if (i > lines_above)
3024 i = lines_above;
3025 if (i)
3027 edit->start_line -= i;
3028 edit->start_display = edit_move_backward (edit, edit->start_display, i);
3029 edit->force |= REDRAW_PAGE;
3030 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
3032 edit_update_curs_row (edit);
3036 /* --------------------------------------------------------------------------------------------- */
3037 /** returns 1 if could scroll, 0 otherwise */
3039 void
3040 edit_scroll_downward (WEdit * edit, int i)
3042 int lines_below;
3043 lines_below = edit->total_lines - edit->start_line - (edit->widget.lines - 1);
3044 if (lines_below > 0)
3046 if (i > lines_below)
3047 i = lines_below;
3048 edit->start_line += i;
3049 edit->start_display = edit_move_forward (edit, edit->start_display, i, 0);
3050 edit->force |= REDRAW_PAGE;
3051 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
3053 edit_update_curs_row (edit);
3056 /* --------------------------------------------------------------------------------------------- */
3058 void
3059 edit_scroll_right (WEdit * edit, int i)
3061 edit->force |= REDRAW_PAGE;
3062 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
3063 edit->start_col -= i;
3066 /* --------------------------------------------------------------------------------------------- */
3068 void
3069 edit_scroll_left (WEdit * edit, int i)
3071 if (edit->start_col)
3073 edit->start_col += i;
3074 if (edit->start_col > 0)
3075 edit->start_col = 0;
3076 edit->force |= REDRAW_PAGE;
3077 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
3081 /* --------------------------------------------------------------------------------------------- */
3082 /* high level cursor movement commands */
3083 /* --------------------------------------------------------------------------------------------- */
3085 void
3086 edit_move_to_prev_col (WEdit * edit, long p)
3088 int prev = edit->prev_col;
3089 int over = edit->over_col;
3090 edit_cursor_move (edit, edit_move_forward3 (edit, p, prev + edit->over_col, 0) - edit->curs1);
3092 if (option_cursor_beyond_eol)
3094 long line_len = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
3095 edit_eol (edit, edit->curs1));
3097 if (line_len < prev + edit->over_col)
3099 edit->over_col = prev + over - line_len;
3100 edit->prev_col = line_len;
3101 edit->curs_col = line_len;
3103 else
3105 edit->curs_col = prev + over;
3106 edit->prev_col = edit->curs_col;
3107 edit->over_col = 0;
3110 else
3112 edit->over_col = 0;
3113 if (is_in_indent (edit) && option_fake_half_tabs)
3115 edit_update_curs_col (edit);
3116 if (space_width)
3117 if (edit->curs_col % (HALF_TAB_SIZE * space_width))
3119 int q = edit->curs_col;
3120 edit->curs_col -= (edit->curs_col % (HALF_TAB_SIZE * space_width));
3121 p = edit_bol (edit, edit->curs1);
3122 edit_cursor_move (edit,
3123 edit_move_forward3 (edit, p, edit->curs_col,
3124 0) - edit->curs1);
3125 if (!left_of_four_spaces (edit))
3126 edit_cursor_move (edit, edit_move_forward3 (edit, p, q, 0) - edit->curs1);
3132 /* --------------------------------------------------------------------------------------------- */
3135 line_is_blank (WEdit * edit, long line)
3137 return is_blank (edit, edit_find_line (edit, line));
3140 /* --------------------------------------------------------------------------------------------- */
3141 /** move cursor to line 'line' */
3143 void
3144 edit_move_to_line (WEdit * e, long line)
3146 if (line < e->curs_line)
3147 edit_move_up (e, e->curs_line - line, 0);
3148 else
3149 edit_move_down (e, line - e->curs_line, 0);
3150 edit_scroll_screen_over_cursor (e);
3153 /* --------------------------------------------------------------------------------------------- */
3154 /** scroll window so that first visible line is 'line' */
3156 void
3157 edit_move_display (WEdit * e, long line)
3159 if (line < e->start_line)
3160 edit_scroll_upward (e, e->start_line - line);
3161 else
3162 edit_scroll_downward (e, line - e->start_line);
3165 /* --------------------------------------------------------------------------------------------- */
3166 /** save markers onto undo stack */
3168 void
3169 edit_push_markers (WEdit * edit)
3171 edit_push_undo_action (edit, MARK_1 + edit->mark1);
3172 edit_push_undo_action (edit, MARK_2 + edit->mark2);
3173 edit_push_undo_action (edit, MARK_CURS + edit->end_mark_curs);
3176 /* --------------------------------------------------------------------------------------------- */
3178 void
3179 edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2)
3181 edit->mark1 = m1;
3182 edit->mark2 = m2;
3183 edit->column1 = c1;
3184 edit->column2 = c2;
3188 /* --------------------------------------------------------------------------------------------- */
3189 /** highlight marker toggle */
3191 void
3192 edit_mark_cmd (WEdit * edit, int unmark)
3194 edit_push_markers (edit);
3195 if (unmark)
3197 edit_set_markers (edit, 0, 0, 0, 0);
3198 edit->force |= REDRAW_PAGE;
3200 else
3202 if (edit->mark2 >= 0)
3204 edit->end_mark_curs = -1;
3205 edit_set_markers (edit, edit->curs1, -1, edit->curs_col + edit->over_col,
3206 edit->curs_col + edit->over_col);
3207 edit->force |= REDRAW_PAGE;
3209 else
3211 edit->end_mark_curs = edit->curs1;
3212 edit_set_markers (edit, edit->mark1, edit->curs1, edit->column1,
3213 edit->curs_col + edit->over_col);
3218 /* --------------------------------------------------------------------------------------------- */
3219 /** highlight the word under cursor */
3221 void
3222 edit_mark_current_word_cmd (WEdit * edit)
3224 long pos;
3226 for (pos = edit->curs1; pos != 0; pos--)
3228 int c1, c2;
3230 c1 = edit_get_byte (edit, pos);
3231 c2 = edit_get_byte (edit, pos - 1);
3232 if (!isspace (c1) && isspace (c2))
3233 break;
3234 if ((my_type_of (c1) & my_type_of (c2)) == 0)
3235 break;
3237 edit->mark1 = pos;
3239 for (; pos < edit->last_byte; pos++)
3241 int c1, c2;
3243 c1 = edit_get_byte (edit, pos);
3244 c2 = edit_get_byte (edit, pos + 1);
3245 if (!isspace (c1) && isspace (c2))
3246 break;
3247 if ((my_type_of (c1) & my_type_of (c2)) == 0)
3248 break;
3250 edit->mark2 = min (pos + 1, edit->last_byte);
3252 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
3255 /* --------------------------------------------------------------------------------------------- */
3257 void
3258 edit_mark_current_line_cmd (WEdit * edit)
3260 long pos = edit->curs1;
3262 edit->mark1 = edit_bol (edit, pos);
3263 edit->mark2 = edit_eol (edit, pos);
3265 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
3268 /* --------------------------------------------------------------------------------------------- */
3270 void
3271 edit_delete_line (WEdit * edit)
3274 * Delete right part of the line.
3275 * Note that edit_get_byte() returns '\n' when byte position is
3276 * beyond EOF.
3278 while (edit_get_byte (edit, edit->curs1) != '\n')
3280 (void) edit_delete (edit, 1);
3284 * Delete '\n' char.
3285 * Note that edit_delete() will not corrupt anything if called while
3286 * cursor position is EOF.
3288 (void) edit_delete (edit, 1);
3291 * Delete left part of the line.
3292 * Note, that edit_get_byte() returns '\n' when byte position is < 0.
3294 while (edit_get_byte (edit, edit->curs1 - 1) != '\n')
3296 (void) edit_backspace (edit, 1);
3300 /* --------------------------------------------------------------------------------------------- */
3302 void
3303 insert_spaces_tab (WEdit * edit, int half)
3305 int i;
3306 edit_update_curs_col (edit);
3307 i = ((edit->curs_col / (option_tab_spacing * space_width / (half + 1))) +
3308 1) * (option_tab_spacing * space_width / (half + 1)) - edit->curs_col;
3309 while (i > 0)
3311 edit_insert (edit, ' ');
3312 i -= space_width;
3316 /* --------------------------------------------------------------------------------------------- */
3319 edit_indent_width (WEdit * edit, long p)
3321 long q = p;
3322 while (strchr ("\t ", edit_get_byte (edit, q)) && q < edit->last_byte - 1) /* move to the end of the leading whitespace of the line */
3323 q++;
3324 return edit_move_forward3 (edit, p, 0, q); /* count the number of columns of indentation */
3327 /* --------------------------------------------------------------------------------------------- */
3329 void
3330 edit_insert_indent (WEdit * edit, int indent)
3332 if (!option_fill_tabs_with_spaces)
3334 while (indent >= TAB_SIZE)
3336 edit_insert (edit, '\t');
3337 indent -= TAB_SIZE;
3340 while (indent-- > 0)
3341 edit_insert (edit, ' ');
3344 /* --------------------------------------------------------------------------------------------- */
3346 void
3347 edit_push_key_press (WEdit * edit)
3349 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
3350 if (edit->mark2 == -1)
3352 edit_push_undo_action (edit, MARK_1 + edit->mark1);
3353 edit_push_undo_action (edit, MARK_CURS + edit->end_mark_curs);
3357 /* --------------------------------------------------------------------------------------------- */
3359 void
3360 edit_find_bracket (WEdit * edit)
3362 edit->bracket = edit_get_bracket (edit, 1, 10000);
3363 if (last_bracket != edit->bracket)
3364 edit->force |= REDRAW_PAGE;
3365 last_bracket = edit->bracket;
3368 /* --------------------------------------------------------------------------------------------- */
3370 * This executes a command as though the user initiated it through a key
3371 * press. Callback with WIDGET_KEY as a message calls this after
3372 * translating the key press. This function can be used to pass any
3373 * command to the editor. Note that the screen wouldn't update
3374 * automatically. Either of command or char_for_insertion must be
3375 * passed as -1. Commands are executed, and char_for_insertion is
3376 * inserted at the cursor.
3379 void
3380 edit_execute_key_command (WEdit * edit, unsigned long command, int char_for_insertion)
3382 if (command == CK_MacroStartRecord || command == CK_RepeatStartRecord
3383 || (macro_index < 0
3384 && (command == CK_MacroStartStopRecord || command == CK_RepeatStartStopRecord)))
3386 macro_index = 0;
3387 edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
3388 return;
3390 if (macro_index != -1)
3392 edit->force |= REDRAW_COMPLETELY;
3393 if (command == CK_MacroStopRecord || command == CK_MacroStartStopRecord)
3395 edit_store_macro_cmd (edit);
3396 macro_index = -1;
3397 return;
3399 else if (command == CK_RepeatStopRecord || command == CK_RepeatStartStopRecord)
3401 edit_repeat_macro_cmd (edit);
3402 macro_index = -1;
3403 return;
3407 if (macro_index >= 0 && macro_index < MAX_MACRO_LENGTH - 1)
3409 record_macro_buf[macro_index].action = command;
3410 record_macro_buf[macro_index++].ch = char_for_insertion;
3412 /* record the beginning of a set of editing actions initiated by a key press */
3413 if (command != CK_Undo && command != CK_ExtendedKeyMap)
3414 edit_push_key_press (edit);
3416 edit_execute_cmd (edit, command, char_for_insertion);
3417 if (edit->column_highlight)
3418 edit->force |= REDRAW_PAGE;
3421 /* --------------------------------------------------------------------------------------------- */
3423 This executes a command at a lower level than macro recording.
3424 It also does not push a key_press onto the undo stack. This means
3425 that if it is called many times, a single undo command will undo
3426 all of them. It also does not check for the Undo command.
3428 void
3429 edit_execute_cmd (WEdit * edit, unsigned long command, int char_for_insertion)
3431 edit->force |= REDRAW_LINE;
3433 /* The next key press will unhighlight the found string, so update
3434 * the whole page */
3435 if (edit->found_len || edit->column_highlight)
3436 edit->force |= REDRAW_PAGE;
3438 switch (command)
3440 /* a mark command with shift-arrow */
3441 case CK_MarkLeft:
3442 case CK_MarkRight:
3443 case CK_MarkToWordBegin:
3444 case CK_MarkToWordEnd:
3445 case CK_MarkToHome:
3446 case CK_MarkToEnd:
3447 case CK_MarkUp:
3448 case CK_MarkDown:
3449 case CK_MarkPageUp:
3450 case CK_MarkPageDown:
3451 case CK_MarkToFileBegin:
3452 case CK_MarkToFileEnd:
3453 case CK_MarkToPageBegin:
3454 case CK_MarkToPageEnd:
3455 case CK_MarkScrollUp:
3456 case CK_MarkScrollDown:
3457 case CK_MarkParagraphUp:
3458 case CK_MarkParagraphDown:
3459 /* a mark command with alt-arrow */
3460 case CK_MarkColumnPageUp:
3461 case CK_MarkColumnPageDown:
3462 case CK_MarkColumnLeft:
3463 case CK_MarkColumnRight:
3464 case CK_MarkColumnUp:
3465 case CK_MarkColumnDown:
3466 case CK_MarkColumnScrollUp:
3467 case CK_MarkColumnScrollDown:
3468 case CK_MarkColumnParagraphUp:
3469 case CK_MarkColumnParagraphDown:
3470 edit->column_highlight = 0;
3471 if (edit->highlight == 0 || (edit->mark2 != -1 && edit->mark1 != edit->mark2))
3473 edit_mark_cmd (edit, 1); /* clear */
3474 edit_mark_cmd (edit, 0); /* marking on */
3476 edit->highlight = 1;
3477 break;
3479 /* any other command */
3480 default:
3481 if (edit->highlight)
3482 edit_mark_cmd (edit, 0); /* clear */
3483 edit->highlight = 0;
3486 /* first check for undo */
3487 if (command == CK_Undo)
3489 edit->redo_stack_reset = 0;
3490 edit_group_undo (edit);
3491 edit->found_len = 0;
3492 edit->prev_col = edit_get_col (edit);
3493 edit->search_start = edit->curs1;
3494 return;
3496 /* check for redo */
3497 if (command == CK_Redo)
3499 edit->redo_stack_reset = 0;
3500 edit_do_redo (edit);
3501 edit->found_len = 0;
3502 edit->prev_col = edit_get_col (edit);
3503 edit->search_start = edit->curs1;
3504 return;
3507 edit->redo_stack_reset = 1;
3509 /* An ordinary key press */
3510 if (char_for_insertion >= 0)
3512 /* if non persistent selection and text selected */
3513 if (!option_persistent_selections)
3515 if (edit->mark1 != edit->mark2)
3516 edit_block_delete_cmd (edit);
3518 if (edit->overwrite)
3520 /* remove char only one time, after input first byte, multibyte chars */
3521 if ((!mc_global.utf8_display || edit->charpoint == 0)
3522 && edit_get_byte (edit, edit->curs1) != '\n')
3523 edit_delete (edit, 0);
3525 if (option_cursor_beyond_eol && edit->over_col > 0)
3526 edit_insert_over (edit);
3527 #ifdef HAVE_CHARSET
3528 if (char_for_insertion > 255 && mc_global.utf8_display == 0)
3530 unsigned char str[6 + 1];
3531 size_t i = 0;
3532 int res = g_unichar_to_utf8 (char_for_insertion, (char *) str);
3533 if (res == 0)
3535 str[0] = '.';
3536 str[1] = '\0';
3538 else
3540 str[res] = '\0';
3542 while (str[i] != 0 && i <= 6)
3544 char_for_insertion = str[i];
3545 edit_insert (edit, char_for_insertion);
3546 i++;
3549 else
3550 #endif
3551 edit_insert (edit, char_for_insertion);
3553 if (option_auto_para_formatting)
3555 format_paragraph (edit, 0);
3556 edit->force |= REDRAW_PAGE;
3558 else
3559 check_and_wrap_line (edit);
3560 edit->found_len = 0;
3561 edit->prev_col = edit_get_col (edit);
3562 edit->search_start = edit->curs1;
3563 edit_find_bracket (edit);
3564 return;
3567 switch (command)
3569 case CK_TopOnScreen:
3570 case CK_BottomOnScreen:
3571 case CK_MarkToPageBegin:
3572 case CK_MarkToPageEnd:
3573 case CK_Up:
3574 case CK_Down:
3575 case CK_Left:
3576 case CK_Right:
3577 case CK_WordLeft:
3578 case CK_WordRight:
3579 if (edit->mark2 >= 0)
3581 if (!option_persistent_selections)
3583 if (edit->column_highlight)
3584 edit_push_undo_action (edit, COLUMN_ON);
3585 edit->column_highlight = 0;
3586 edit_mark_cmd (edit, 1);
3591 switch (command)
3593 case CK_TopOnScreen:
3594 case CK_BottomOnScreen:
3595 case CK_MarkToPageBegin:
3596 case CK_MarkToPageEnd:
3597 case CK_Up:
3598 case CK_Down:
3599 case CK_WordLeft:
3600 case CK_WordRight:
3601 case CK_MarkToWordBegin:
3602 case CK_MarkToWordEnd:
3603 case CK_MarkUp:
3604 case CK_MarkDown:
3605 case CK_MarkColumnUp:
3606 case CK_MarkColumnDown:
3607 if (edit->mark2 == -1)
3608 break; /*marking is following the cursor: may need to highlight a whole line */
3609 case CK_Left:
3610 case CK_Right:
3611 case CK_MarkLeft:
3612 case CK_MarkRight:
3613 edit->force |= REDRAW_CHAR_ONLY;
3616 /* basic cursor key commands */
3617 switch (command)
3619 case CK_BackSpace:
3620 /* if non persistent selection and text selected */
3621 if (!option_persistent_selections)
3623 if (edit->mark1 != edit->mark2)
3625 edit_block_delete_cmd (edit);
3626 break;
3629 if (option_cursor_beyond_eol && edit->over_col > 0)
3631 edit->over_col--;
3632 break;
3634 if (option_backspace_through_tabs && is_in_indent (edit))
3636 while (edit_get_byte (edit, edit->curs1 - 1) != '\n' && edit->curs1 > 0)
3637 edit_backspace (edit, 1);
3638 break;
3640 else
3642 if (option_fake_half_tabs)
3644 int i;
3645 if (is_in_indent (edit) && right_of_four_spaces (edit))
3647 for (i = 0; i < HALF_TAB_SIZE; i++)
3648 edit_backspace (edit, 1);
3649 break;
3653 edit_backspace (edit, 0);
3654 break;
3655 case CK_Delete:
3656 /* if non persistent selection and text selected */
3657 if (!option_persistent_selections)
3659 if (edit->mark1 != edit->mark2)
3661 edit_block_delete_cmd (edit);
3662 break;
3666 if (option_cursor_beyond_eol && edit->over_col > 0)
3667 edit_insert_over (edit);
3669 if (option_fake_half_tabs)
3671 int i;
3672 if (is_in_indent (edit) && left_of_four_spaces (edit))
3674 for (i = 1; i <= HALF_TAB_SIZE; i++)
3675 edit_delete (edit, 1);
3676 break;
3679 edit_delete (edit, 0);
3680 break;
3681 case CK_DeleteToWordBegin:
3682 edit->over_col = 0;
3683 edit_left_delete_word (edit);
3684 break;
3685 case CK_DeleteToWordEnd:
3686 if (option_cursor_beyond_eol && edit->over_col > 0)
3687 edit_insert_over (edit);
3689 edit_right_delete_word (edit);
3690 break;
3691 case CK_DeleteLine:
3692 edit_delete_line (edit);
3693 break;
3694 case CK_DeleteToHome:
3695 edit_delete_to_line_begin (edit);
3696 break;
3697 case CK_DeleteToEnd:
3698 edit_delete_to_line_end (edit);
3699 break;
3700 case CK_Enter:
3701 edit->over_col = 0;
3702 if (option_auto_para_formatting)
3704 edit_double_newline (edit);
3705 if (option_return_does_auto_indent)
3706 edit_auto_indent (edit);
3707 format_paragraph (edit, 0);
3709 else
3711 edit_insert (edit, '\n');
3712 if (option_return_does_auto_indent)
3714 edit_auto_indent (edit);
3717 break;
3718 case CK_Return:
3719 edit_insert (edit, '\n');
3720 break;
3722 case CK_MarkColumnPageUp:
3723 edit->column_highlight = 1;
3724 case CK_PageUp:
3725 case CK_MarkPageUp:
3726 edit_move_up (edit, edit->widget.lines - 1, 1);
3727 break;
3728 case CK_MarkColumnPageDown:
3729 edit->column_highlight = 1;
3730 case CK_PageDown:
3731 case CK_MarkPageDown:
3732 edit_move_down (edit, edit->widget.lines - 1, 1);
3733 break;
3734 case CK_MarkColumnLeft:
3735 edit->column_highlight = 1;
3736 case CK_Left:
3737 case CK_MarkLeft:
3738 if (option_fake_half_tabs)
3740 if (is_in_indent (edit) && right_of_four_spaces (edit))
3742 if (option_cursor_beyond_eol && edit->over_col > 0)
3743 edit->over_col--;
3744 else
3745 edit_cursor_move (edit, -HALF_TAB_SIZE);
3746 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
3747 break;
3750 edit_left_char_move_cmd (edit);
3751 break;
3752 case CK_MarkColumnRight:
3753 edit->column_highlight = 1;
3754 case CK_Right:
3755 case CK_MarkRight:
3756 if (option_fake_half_tabs)
3758 if (is_in_indent (edit) && left_of_four_spaces (edit))
3760 edit_cursor_move (edit, HALF_TAB_SIZE);
3761 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
3762 break;
3765 edit_right_char_move_cmd (edit);
3766 break;
3767 case CK_TopOnScreen:
3768 case CK_MarkToPageBegin:
3769 edit_begin_page (edit);
3770 break;
3771 case CK_BottomOnScreen:
3772 case CK_MarkToPageEnd:
3773 edit_end_page (edit);
3774 break;
3775 case CK_WordLeft:
3776 case CK_MarkToWordBegin:
3777 edit->over_col = 0;
3778 edit_left_word_move_cmd (edit);
3779 break;
3780 case CK_WordRight:
3781 case CK_MarkToWordEnd:
3782 edit->over_col = 0;
3783 edit_right_word_move_cmd (edit);
3784 break;
3785 case CK_MarkColumnUp:
3786 edit->column_highlight = 1;
3787 case CK_Up:
3788 case CK_MarkUp:
3789 edit_move_up (edit, 1, 0);
3790 break;
3791 case CK_MarkColumnDown:
3792 edit->column_highlight = 1;
3793 case CK_Down:
3794 case CK_MarkDown:
3795 edit_move_down (edit, 1, 0);
3796 break;
3797 case CK_MarkColumnParagraphUp:
3798 edit->column_highlight = 1;
3799 case CK_ParagraphUp:
3800 case CK_MarkParagraphUp:
3801 edit_move_up_paragraph (edit, 0);
3802 break;
3803 case CK_MarkColumnParagraphDown:
3804 edit->column_highlight = 1;
3805 case CK_ParagraphDown:
3806 case CK_MarkParagraphDown:
3807 edit_move_down_paragraph (edit, 0);
3808 break;
3809 case CK_MarkColumnScrollUp:
3810 edit->column_highlight = 1;
3811 case CK_ScrollUp:
3812 case CK_MarkScrollUp:
3813 edit_move_up (edit, 1, 1);
3814 break;
3815 case CK_MarkColumnScrollDown:
3816 edit->column_highlight = 1;
3817 case CK_ScrollDown:
3818 case CK_MarkScrollDown:
3819 edit_move_down (edit, 1, 1);
3820 break;
3821 case CK_Home:
3822 case CK_MarkToHome:
3823 edit_cursor_to_bol (edit);
3824 break;
3825 case CK_End:
3826 case CK_MarkToEnd:
3827 edit_cursor_to_eol (edit);
3828 break;
3829 case CK_Tab:
3830 /* if text marked shift block */
3831 if (edit->mark1 != edit->mark2 && !option_persistent_selections)
3833 if (edit->mark2 < 0)
3834 edit_mark_cmd (edit, 0);
3835 edit_move_block_to_right (edit);
3837 else
3839 if (option_cursor_beyond_eol)
3840 edit_insert_over (edit);
3841 edit_tab_cmd (edit);
3842 if (option_auto_para_formatting)
3844 format_paragraph (edit, 0);
3845 edit->force |= REDRAW_PAGE;
3847 else
3849 check_and_wrap_line (edit);
3852 break;
3854 case CK_InsertOverwrite:
3855 edit->overwrite = !edit->overwrite;
3856 break;
3858 case CK_Mark:
3859 if (edit->mark2 >= 0)
3861 if (edit->column_highlight)
3862 edit_push_undo_action (edit, COLUMN_ON);
3863 edit->column_highlight = 0;
3865 edit_mark_cmd (edit, 0);
3866 break;
3867 case CK_MarkColumn:
3868 if (!edit->column_highlight)
3869 edit_push_undo_action (edit, COLUMN_OFF);
3870 edit->column_highlight = 1;
3871 edit_mark_cmd (edit, 0);
3872 break;
3873 case CK_MarkAll:
3874 edit_set_markers (edit, 0, edit->last_byte, 0, 0);
3875 edit->force |= REDRAW_PAGE;
3876 break;
3877 case CK_Unmark:
3878 if (edit->column_highlight)
3879 edit_push_undo_action (edit, COLUMN_ON);
3880 edit->column_highlight = 0;
3881 edit_mark_cmd (edit, 1);
3882 break;
3883 case CK_MarkWord:
3884 if (edit->column_highlight)
3885 edit_push_undo_action (edit, COLUMN_ON);
3886 edit->column_highlight = 0;
3887 edit_mark_current_word_cmd (edit);
3888 break;
3889 case CK_MarkLine:
3890 if (edit->column_highlight)
3891 edit_push_undo_action (edit, COLUMN_ON);
3892 edit->column_highlight = 0;
3893 edit_mark_current_line_cmd (edit);
3894 break;
3896 case CK_ShowNumbers:
3897 option_line_state = !option_line_state;
3898 option_line_state_width = option_line_state ? LINE_STATE_WIDTH : 0;
3899 edit->force |= REDRAW_PAGE;
3900 break;
3902 case CK_ShowMargin:
3903 show_right_margin = !show_right_margin;
3904 edit->force |= REDRAW_PAGE;
3905 break;
3907 case CK_Bookmark:
3908 book_mark_clear (edit, edit->curs_line, BOOK_MARK_FOUND_COLOR);
3909 if (book_mark_query_color (edit, edit->curs_line, BOOK_MARK_COLOR))
3910 book_mark_clear (edit, edit->curs_line, BOOK_MARK_COLOR);
3911 else
3912 book_mark_insert (edit, edit->curs_line, BOOK_MARK_COLOR);
3913 break;
3914 case CK_BookmarkFlush:
3915 book_mark_flush (edit, BOOK_MARK_COLOR);
3916 book_mark_flush (edit, BOOK_MARK_FOUND_COLOR);
3917 edit->force |= REDRAW_PAGE;
3918 break;
3919 case CK_BookmarkNext:
3920 if (edit->book_mark)
3922 struct _book_mark *p;
3923 p = (struct _book_mark *) book_mark_find (edit, edit->curs_line);
3924 if (p->next)
3926 p = p->next;
3927 if (p->line >= edit->start_line + edit->widget.lines || p->line < edit->start_line)
3928 edit_move_display (edit, p->line - edit->widget.lines / 2);
3929 edit_move_to_line (edit, p->line);
3932 break;
3933 case CK_BookmarkPrev:
3934 if (edit->book_mark)
3936 struct _book_mark *p;
3937 p = (struct _book_mark *) book_mark_find (edit, edit->curs_line);
3938 while (p->line == edit->curs_line)
3939 if (p->prev)
3940 p = p->prev;
3941 if (p->line >= 0)
3943 if (p->line >= edit->start_line + edit->widget.lines || p->line < edit->start_line)
3944 edit_move_display (edit, p->line - edit->widget.lines / 2);
3945 edit_move_to_line (edit, p->line);
3948 break;
3950 case CK_Top:
3951 case CK_MarkToFileBegin:
3952 edit_move_to_top (edit);
3953 break;
3954 case CK_Bottom:
3955 case CK_MarkToFileEnd:
3956 edit_move_to_bottom (edit);
3957 break;
3959 case CK_Copy:
3960 if (option_cursor_beyond_eol && edit->over_col > 0)
3961 edit_insert_over (edit);
3962 edit_block_copy_cmd (edit);
3963 break;
3964 case CK_Remove:
3965 edit_block_delete_cmd (edit);
3966 break;
3967 case CK_Move:
3968 edit_block_move_cmd (edit);
3969 break;
3971 case CK_BlockShiftLeft:
3972 if (edit->mark1 != edit->mark2)
3973 edit_move_block_to_left (edit);
3974 break;
3975 case CK_BlockShiftRight:
3976 if (edit->mark1 != edit->mark2)
3977 edit_move_block_to_right (edit);
3978 break;
3979 case CK_Store:
3980 edit_copy_to_X_buf_cmd (edit);
3981 break;
3982 case CK_Cut:
3983 edit_cut_to_X_buf_cmd (edit);
3984 break;
3985 case CK_Paste:
3986 /* if non persistent selection and text selected */
3987 if (!option_persistent_selections)
3989 if (edit->mark1 != edit->mark2)
3990 edit_block_delete_cmd (edit);
3992 if (option_cursor_beyond_eol && edit->over_col > 0)
3993 edit_insert_over (edit);
3994 edit_paste_from_X_buf_cmd (edit);
3995 break;
3996 case CK_History:
3997 edit_paste_from_history (edit);
3998 break;
4000 case CK_SaveAs:
4001 edit_save_as_cmd (edit);
4002 break;
4003 case CK_Save:
4004 edit_save_confirm_cmd (edit);
4005 break;
4006 case CK_EditFile:
4007 edit_load_cmd (edit, EDIT_FILE_COMMON);
4008 break;
4009 case CK_BlockSave:
4010 edit_save_block_cmd (edit);
4011 break;
4012 case CK_InsertFile:
4013 edit_insert_file_cmd (edit);
4014 break;
4016 case CK_FilePrev:
4017 edit_load_back_cmd (edit);
4018 break;
4019 case CK_FileNext:
4020 edit_load_forward_cmd (edit);
4021 break;
4023 case CK_EditSyntaxFile:
4024 edit_load_cmd (edit, EDIT_FILE_SYNTAX);
4025 break;
4026 case CK_SyntaxChoose:
4027 edit_syntax_dialog (edit);
4028 break;
4030 case CK_EditUserMenu:
4031 edit_load_cmd (edit, EDIT_FILE_MENU);
4032 break;
4034 case CK_SyntaxOnOff:
4035 option_syntax_highlighting ^= 1;
4036 if (option_syntax_highlighting == 1)
4037 edit_load_syntax (edit, NULL, edit->syntax_type);
4038 edit->force |= REDRAW_PAGE;
4039 break;
4041 case CK_ShowTabTws:
4042 enable_show_tabs_tws ^= 1;
4043 edit->force |= REDRAW_PAGE;
4044 break;
4046 case CK_Search:
4047 edit_search_cmd (edit, FALSE);
4048 break;
4049 case CK_SearchContinue:
4050 edit_search_cmd (edit, TRUE);
4051 break;
4052 case CK_Replace:
4053 edit_replace_cmd (edit, 0);
4054 break;
4055 case CK_ReplaceContinue:
4056 edit_replace_cmd (edit, 1);
4057 break;
4058 case CK_Complete:
4059 /* if text marked shift block */
4060 if (edit->mark1 != edit->mark2 && !option_persistent_selections)
4062 edit_move_block_to_left (edit);
4064 else
4066 edit_complete_word_cmd (edit);
4068 break;
4069 case CK_Find:
4070 edit_get_match_keyword_cmd (edit);
4071 break;
4072 case CK_Quit:
4073 dlg_stop (edit->widget.owner);
4074 break;
4075 case CK_EditNew:
4076 edit_new_cmd (edit);
4077 break;
4078 case CK_Help:
4079 edit_help_cmd (edit);
4080 break;
4081 case CK_Refresh:
4082 edit_refresh_cmd (edit);
4083 break;
4084 case CK_SaveSetup:
4085 save_setup_cmd ();
4086 break;
4087 case CK_About:
4088 edit_about ();
4089 break;
4090 case CK_LearnKeys:
4091 learn_keys ();
4092 break;
4093 case CK_Options:
4094 edit_options_dialog (edit);
4095 break;
4096 case CK_OptionsSaveMode:
4097 menu_save_mode_cmd ();
4098 break;
4099 case CK_Date:
4101 char s[BUF_MEDIUM];
4102 /* fool gcc to prevent a Y2K warning */
4103 char time_format[] = "_c";
4104 time_format[0] = '%';
4106 FMT_LOCALTIME_CURRENT (s, sizeof (s), time_format);
4107 edit_print_string (edit, s);
4108 edit->force |= REDRAW_PAGE;
4109 break;
4111 break;
4112 case CK_Goto:
4113 edit_goto_cmd (edit);
4114 break;
4115 case CK_ParagraphFormat:
4116 format_paragraph (edit, 1);
4117 edit->force |= REDRAW_PAGE;
4118 break;
4119 case CK_MacroDelete:
4120 edit_delete_macro_cmd (edit);
4121 break;
4122 case CK_MatchBracket:
4123 edit_goto_matching_bracket (edit);
4124 break;
4125 case CK_UserMenu:
4126 user_menu (edit, NULL, -1);
4127 break;
4128 case CK_Sort:
4129 edit_sort_cmd (edit);
4130 break;
4131 case CK_ExternalCommand:
4132 edit_ext_cmd (edit);
4133 break;
4134 case CK_Mail:
4135 edit_mail_dialog (edit);
4136 break;
4137 case CK_Shell:
4138 view_other_cmd ();
4139 break;
4140 #ifdef HAVE_CHARSET
4141 case CK_SelectCodepage:
4142 edit_select_codepage_cmd (edit);
4143 break;
4144 #endif
4145 case CK_InsertLiteral:
4146 edit_insert_literal_cmd (edit);
4147 break;
4148 case CK_MacroStartStopRecord:
4149 edit_begin_end_macro_cmd (edit);
4150 break;
4151 case CK_RepeatStartStopRecord:
4152 edit_begin_end_repeat_cmd (edit);
4153 break;
4154 case CK_ExtendedKeyMap:
4155 edit->extmod = 1;
4156 break;
4157 default:
4158 break;
4161 /* CK_PipeBlock */
4162 if ((command / CK_PipeBlock (0)) == 1)
4163 edit_block_process_cmd (edit, command - CK_PipeBlock (0));
4165 /* keys which must set the col position, and the search vars */
4166 switch (command)
4168 case CK_Search:
4169 case CK_SearchContinue:
4170 case CK_Replace:
4171 case CK_ReplaceContinue:
4172 case CK_Complete:
4173 edit->prev_col = edit_get_col (edit);
4174 break;
4175 case CK_Up:
4176 case CK_MarkUp:
4177 case CK_MarkColumnUp:
4178 case CK_Down:
4179 case CK_MarkDown:
4180 case CK_MarkColumnDown:
4181 case CK_PageUp:
4182 case CK_MarkPageUp:
4183 case CK_MarkColumnPageUp:
4184 case CK_PageDown:
4185 case CK_MarkPageDown:
4186 case CK_MarkColumnPageDown:
4187 case CK_Top:
4188 case CK_MarkToFileBegin:
4189 case CK_Bottom:
4190 case CK_MarkToFileEnd:
4191 case CK_ParagraphUp:
4192 case CK_MarkParagraphUp:
4193 case CK_MarkColumnParagraphUp:
4194 case CK_ParagraphDown:
4195 case CK_MarkParagraphDown:
4196 case CK_MarkColumnParagraphDown:
4197 case CK_ScrollUp:
4198 case CK_MarkScrollUp:
4199 case CK_MarkColumnScrollUp:
4200 case CK_ScrollDown:
4201 case CK_MarkScrollDown:
4202 case CK_MarkColumnScrollDown:
4203 edit->search_start = edit->curs1;
4204 edit->found_len = 0;
4205 break;
4206 default:
4207 edit->found_len = 0;
4208 edit->prev_col = edit_get_col (edit);
4209 edit->search_start = edit->curs1;
4211 edit_find_bracket (edit);
4213 if (option_auto_para_formatting)
4215 switch (command)
4217 case CK_BackSpace:
4218 case CK_Delete:
4219 case CK_DeleteToWordBegin:
4220 case CK_DeleteToWordEnd:
4221 case CK_DeleteToHome:
4222 case CK_DeleteToEnd:
4223 format_paragraph (edit, 0);
4224 edit->force |= REDRAW_PAGE;
4229 /* --------------------------------------------------------------------------------------------- */
4231 void
4232 edit_stack_init (void)
4234 for (edit_stack_iterator = 0; edit_stack_iterator < MAX_HISTORY_MOVETO; edit_stack_iterator++)
4236 edit_history_moveto[edit_stack_iterator].filename = NULL;
4237 edit_history_moveto[edit_stack_iterator].line = -1;
4240 edit_stack_iterator = 0;
4243 /* --------------------------------------------------------------------------------------------- */
4245 void
4246 edit_stack_free (void)
4248 for (edit_stack_iterator = 0; edit_stack_iterator < MAX_HISTORY_MOVETO; edit_stack_iterator++)
4249 g_free (edit_history_moveto[edit_stack_iterator].filename);
4252 /* --------------------------------------------------------------------------------------------- */
4253 /** move i lines */
4255 void
4256 edit_move_up (WEdit * edit, unsigned long i, int do_scroll)
4258 edit_move_updown (edit, i, do_scroll, TRUE);
4261 /* --------------------------------------------------------------------------------------------- */
4262 /** move i lines */
4264 void
4265 edit_move_down (WEdit * edit, unsigned long i, int do_scroll)
4267 edit_move_updown (edit, i, do_scroll, FALSE);
4270 /* --------------------------------------------------------------------------------------------- */
4272 unsigned int
4273 edit_unlock_file (WEdit * edit)
4275 char *fullpath;
4276 unsigned int ret;
4278 fullpath = mc_build_filename (edit->dir, edit->filename, (char *) NULL);
4279 ret = unlock_file (fullpath);
4280 g_free (fullpath);
4282 return ret;
4285 /* --------------------------------------------------------------------------------------------- */
4287 unsigned int
4288 edit_lock_file (WEdit * edit)
4290 char *fullpath;
4291 unsigned int ret;
4293 fullpath = mc_build_filename (edit->dir, edit->filename, (char *) NULL);
4294 ret = lock_file (fullpath);
4295 g_free (fullpath);
4297 return ret;
4300 /* --------------------------------------------------------------------------------------------- */