g_string_sprintf() is deprecated.
[midnight-commander.git] / src / editor / edit.c
blob2a74599ece6b8d47edf94e1c3d61e96a80293967
1 /* editor low level data handling and cursor fundamentals.
3 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007 Free Software Foundation, Inc.
6 Authors: 1996, 1997 Paul Sheer
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
24 /** \file
25 * \brief Source: editor low level data handling and cursor fundamentals
26 * \author Paul Sheer
27 * \date 1996, 1997
30 #include <config.h>
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <sys/stat.h>
39 #include <stdlib.h>
40 #include <fcntl.h>
42 #include "lib/global.h"
44 #include "lib/tty/color.h"
45 #include "lib/tty/tty.h" /* attrset() */
46 #include "lib/tty/key.h" /* is_idle() */
47 #include "lib/skin.h" /* EDITOR_NORMAL_COLOR */
48 #include "lib/vfs/mc-vfs/vfs.h"
49 #include "lib/strutil.h" /* utf string functions */
51 #include "src/widget.h"
52 #include "src/cmd.h" /* view_other_cmd() */
53 #include "src/user.h" /* user_menu_cmd() */
54 #include "src/wtools.h" /* query_dialog() */
55 #include "lib/timefmt.h" /* time formatting */
56 #include "src/charsets.h" /* get_codepage_id */
57 #include "src/main.h" /* source_codepage */
58 #include "src/learn.h" /* learn_keys */
59 #include "src/cmddef.h"
60 #include "src/keybind.h"
62 #include "edit-impl.h"
63 #include "editlock.h"
64 #include "edit-widget.h"
67 int option_word_wrap_line_length = 72;
68 int option_typewriter_wrap = 0;
69 int option_auto_para_formatting = 0;
70 int option_fill_tabs_with_spaces = 0;
71 int option_return_does_auto_indent = 1;
72 int option_backspace_through_tabs = 0;
73 int option_fake_half_tabs = 1;
74 int option_save_mode = EDIT_QUICK_SAVE;
75 int option_save_position = 1;
76 int option_max_undo = 32768;
77 int option_persistent_selections = 1;
78 int option_cursor_beyond_eol = 0;
79 int option_line_state = 0;
80 int option_line_state_width = 0;
82 int option_edit_right_extreme = 0;
83 int option_edit_left_extreme = 0;
84 int option_edit_top_extreme = 0;
85 int option_edit_bottom_extreme = 0;
86 int enable_show_tabs_tws = 1;
87 int option_check_nl_at_eof = 0;
88 int show_right_margin = 0;
90 const char *option_whole_chars_search = "0123456789abcdefghijklmnopqrstuvwxyz_";
91 char *option_backup_ext = NULL;
93 int edit_stack_iterator = 0;
94 edit_stack_type edit_history_moveto[MAX_HISTORY_MOVETO];
95 /* magic sequense for say than block is vertical */
96 const char VERTICAL_MAGIC[] = { '\1', '\1', '\1', '\1', '\n' };
98 /*-
100 * here's a quick sketch of the layout: (don't run this through indent.)
102 * (b1 is buffers1 and b2 is buffers2)
105 * \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
106 * ______________________________________|______________________________________
108 * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
109 * |-> |-> |-> |-> |-> |-> |
111 * _<------------------------->|<----------------->_
112 * WEdit->curs2 | WEdit->curs1
113 * ^ | ^
114 * | ^|^ |
115 * cursor ||| cursor
116 * |||
117 * file end|||file beginning
122 * This_is_some_file
123 * fin.
126 static void user_menu (WEdit * edit);
129 edit_get_byte (WEdit * edit, long byte_index)
131 unsigned long p;
132 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
133 return '\n';
135 if (byte_index >= edit->curs1)
137 p = edit->curs1 + edit->curs2 - byte_index - 1;
138 return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1];
140 else
142 return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE];
146 char *
147 edit_get_byte_ptr (WEdit * edit, long byte_index)
149 unsigned long p;
150 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
151 return NULL;
153 if (byte_index >= edit->curs1)
155 p = edit->curs1 + edit->curs2 - byte_index - 1;
156 return (char *) (edit->buffers2[p >> S_EDIT_BUF_SIZE] +
157 (EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1));
159 else
161 return (char *) (edit->buffers1[byte_index >> S_EDIT_BUF_SIZE] +
162 (byte_index & M_EDIT_BUF_SIZE));
166 char *
167 edit_get_buf_ptr (WEdit * edit, long byte_index)
169 unsigned long p;
171 if (byte_index >= (edit->curs1 + edit->curs2))
172 byte_index--;
174 if (byte_index < 0)
175 return NULL;
177 if (byte_index >= edit->curs1)
179 p = edit->curs1 + edit->curs2 - 1;
180 return (char *) (edit->buffers2[p >> S_EDIT_BUF_SIZE] +
181 (EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1));
183 else
185 return (char *) (edit->buffers1[byte_index >> S_EDIT_BUF_SIZE] + (0 & M_EDIT_BUF_SIZE));
190 edit_get_utf (WEdit * edit, long byte_index, int *char_width)
192 gchar *str = NULL;
193 int res = -1;
194 gunichar ch;
195 gchar *next_ch = NULL;
196 int width = 0;
198 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
200 *char_width = 0;
201 return '\n';
204 str = edit_get_byte_ptr (edit, byte_index);
206 if (str == NULL)
208 *char_width = 0;
209 return 0;
212 res = g_utf8_get_char_validated (str, -1);
214 if (res < 0)
216 ch = *str;
217 width = 0;
219 else
221 ch = res;
222 /* Calculate UTF-8 char width */
223 next_ch = g_utf8_next_char (str);
224 if (next_ch)
226 width = next_ch - str;
228 else
230 ch = 0;
231 width = 0;
234 *char_width = width;
235 return ch;
239 edit_get_prev_utf (WEdit * edit, long byte_index, int *char_width)
241 gchar *str, *buf = NULL;
242 int res = -1;
243 gunichar ch;
244 gchar *next_ch = NULL;
245 int width = 0;
247 if (byte_index > 0)
248 byte_index--;
250 if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
252 *char_width = 0;
253 return 0;
256 ch = edit_get_utf (edit, byte_index, &width);
258 if (width == 1)
260 *char_width = width;
261 return ch;
264 str = edit_get_byte_ptr (edit, byte_index);
265 buf = edit_get_buf_ptr (edit, byte_index);
266 if (str == NULL || buf == NULL)
268 *char_width = 0;
269 return 0;
271 /* get prev utf8 char */
272 if (str != buf)
273 str = g_utf8_find_prev_char (buf, str);
275 res = g_utf8_get_char_validated (str, -1);
277 if (res < 0)
279 ch = *str;
280 width = 0;
282 else
284 ch = res;
285 /* Calculate UTF-8 char width */
286 next_ch = g_utf8_next_char (str);
287 if (next_ch)
289 width = next_ch - str;
291 else
293 ch = 0;
294 width = 0;
297 *char_width = width;
298 return ch;
302 * Initialize the buffers for an empty files.
304 static void
305 edit_init_buffers (WEdit * edit)
307 int j;
309 for (j = 0; j <= MAXBUFF; j++)
311 edit->buffers1[j] = NULL;
312 edit->buffers2[j] = NULL;
315 edit->curs1 = 0;
316 edit->curs2 = 0;
317 edit->buffers2[0] = g_malloc0 (EDIT_BUF_SIZE);
321 * Load file OR text into buffers. Set cursor to the beginning of file.
322 * Return 1 on error.
324 static int
325 edit_load_file_fast (WEdit * edit, const char *filename)
327 long buf, buf2;
328 int file = -1;
329 int ret = 1;
331 edit->curs2 = edit->last_byte;
332 buf2 = edit->curs2 >> S_EDIT_BUF_SIZE;
333 edit->utf8 = 0;
335 file = mc_open (filename, O_RDONLY | O_BINARY);
336 if (file == -1)
338 gchar *errmsg;
340 errmsg = g_strdup_printf (_("Cannot open %s for reading"), filename);
341 edit_error_dialog (_("Error"), errmsg);
342 g_free (errmsg);
343 return 1;
346 if (!edit->buffers2[buf2])
347 edit->buffers2[buf2] = g_malloc0 (EDIT_BUF_SIZE);
351 if (mc_read (file,
352 (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE -
353 (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE) < 0)
354 break;
356 for (buf = buf2 - 1; buf >= 0; buf--)
358 /* edit->buffers2[0] is already allocated */
359 if (!edit->buffers2[buf])
360 edit->buffers2[buf] = g_malloc0 (EDIT_BUF_SIZE);
361 if (mc_read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE) < 0)
362 break;
364 ret = 0;
366 while (0);
367 if (ret)
369 char *err_str = g_strdup_printf (_("Error reading %s"), filename);
370 edit_error_dialog (_("Error"), err_str);
371 g_free (err_str);
373 mc_close (file);
374 return ret;
377 /* detecting an error on save is easy: just check if every byte has been written. */
378 /* detecting an error on read, is not so easy 'cos there is not way to tell
379 whether you read everything or not. */
380 /* FIXME: add proper `triple_pipe_open' to read, write and check errors. */
381 static const struct edit_filters
383 const char *read, *write, *extension;
384 } all_filters[] =
386 /* *INDENT-OFF* */
387 { "xz -cd %s 2>&1", "xz > %s", ".xz"},
388 { "lzma -cd %s 2>&1", "lzma > %s", ".lzma" },
389 { "bzip2 -cd %s 2>&1", "bzip2 > %s", ".bz2" },
390 { "gzip -cd %s 2>&1", "gzip > %s", ".gz" },
391 { "gzip -cd %s 2>&1", "gzip > %s", ".Z" }
392 /* *INDENT-ON* */
395 /* Return index of the filter or -1 is there is no appropriate filter */
396 static int
397 edit_find_filter (const char *filename)
399 size_t i, l, e;
401 if (filename == NULL)
402 return -1;
404 l = strlen (filename);
405 for (i = 0; i < sizeof (all_filters) / sizeof (all_filters[0]); i++)
407 e = strlen (all_filters[i].extension);
408 if (l > e)
409 if (!strcmp (all_filters[i].extension, filename + l - e))
410 return i;
412 return -1;
415 static char *
416 edit_get_filter (const char *filename)
418 int i;
419 char *p, *quoted_name;
421 i = edit_find_filter (filename);
422 if (i < 0)
423 return NULL;
425 quoted_name = name_quote (filename, 0);
426 p = g_strdup_printf (all_filters[i].read, quoted_name);
427 g_free (quoted_name);
428 return p;
431 char *
432 edit_get_write_filter (const char *write_name, const char *filename)
434 int i;
435 char *p, *writename;
437 i = edit_find_filter (filename);
438 if (i < 0)
439 return NULL;
441 writename = name_quote (write_name, 0);
442 p = g_strdup_printf (all_filters[i].write, writename);
443 g_free (writename);
444 return p;
447 static long
448 edit_insert_stream (WEdit * edit, FILE * f)
450 int c;
451 long i = 0;
452 while ((c = fgetc (f)) >= 0)
454 edit_insert (edit, c);
455 i++;
457 return i;
460 long
461 edit_write_stream (WEdit * edit, FILE * f)
463 long i;
465 if (edit->lb == LB_ASIS)
467 for (i = 0; i < edit->last_byte; i++)
468 if (fputc (edit_get_byte (edit, i), f) < 0)
469 break;
470 return i;
473 /* change line breaks */
474 for (i = 0; i < edit->last_byte; i++)
476 unsigned char c = edit_get_byte (edit, i);
478 if (!(c == '\n' || c == '\r'))
480 /* not line break */
481 if (fputc (c, f) < 0)
482 return i;
484 else
485 { /* (c == '\n' || c == '\r') */
486 unsigned char c1 = edit_get_byte (edit, i + 1); /* next char */
488 switch (edit->lb)
490 case LB_UNIX: /* replace "\r\n" or '\r' to '\n' */
491 /* put one line break unconditionally */
492 if (fputc ('\n', f) < 0)
493 return i;
495 i++; /* 2 chars are processed */
497 if (c == '\r' && c1 == '\n')
498 /* Windows line break; go to the next char */
499 break;
501 if (c == '\r' && c1 == '\r')
503 /* two Macintosh line breaks; put second line break */
504 if (fputc ('\n', f) < 0)
505 return i;
506 break;
509 if (fputc (c1, f) < 0)
510 return i;
511 break;
513 case LB_WIN: /* replace '\n' or '\r' to "\r\n" */
514 /* put one line break unconditionally */
515 if (fputc ('\r', f) < 0 || fputc ('\n', f) < 0)
516 return i;
518 if (c == '\r' && c1 == '\n')
519 /* Windows line break; go to the next char */
520 i++;
521 break;
523 case LB_MAC: /* replace "\r\n" or '\n' to '\r' */
524 /* put one line break unconditionally */
525 if (fputc ('\r', f) < 0)
526 return i;
528 i++; /* 2 chars are processed */
530 if (c == '\r' && c1 == '\n')
531 /* Windows line break; go to the next char */
532 break;
534 if (c == '\n' && c1 == '\n')
536 /* two Windows line breaks; put second line break */
537 if (fputc ('\r', f) < 0)
538 return i;
539 break;
542 if (fputc (c1, f) < 0)
543 return i;
544 break;
545 case LB_ASIS: /* default without changes */
546 break;
551 return edit->last_byte;
554 #define TEMP_BUF_LEN 1024
556 /* inserts a file at the cursor, returns 1 on success */
558 edit_insert_file (WEdit * edit, const char *filename)
560 char *p;
562 p = edit_get_filter (filename);
563 if (p != NULL)
565 FILE *f;
566 long current = edit->curs1;
567 f = (FILE *) popen (p, "r");
568 if (f != NULL)
570 edit_insert_stream (edit, f);
571 edit_cursor_move (edit, current - edit->curs1);
572 if (pclose (f) > 0)
574 char *errmsg;
575 errmsg = g_strdup_printf (_("Error reading from pipe: %s"), p);
576 edit_error_dialog (_("Error"), errmsg);
577 g_free (errmsg);
578 g_free (p);
579 return 0;
582 else
584 char *errmsg;
585 errmsg = g_strdup_printf (_("Cannot open pipe for reading: %s"), p);
586 edit_error_dialog (_("Error"), errmsg);
587 g_free (errmsg);
588 g_free (p);
589 return 0;
591 g_free (p);
593 else
595 int i, file, blocklen;
596 long current = edit->curs1;
597 int vertical_insertion = 0;
598 char *buf;
599 file = mc_open (filename, O_RDONLY | O_BINARY);
600 if (file == -1)
601 return 0;
602 buf = g_malloc0 (TEMP_BUF_LEN);
603 blocklen = mc_read (file, buf, sizeof (VERTICAL_MAGIC));
604 if (blocklen > 0)
606 /* if contain signature VERTICAL_MAGIC tnen it vertical block */
607 if (memcmp (buf, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC)) == 0)
608 vertical_insertion = 1;
609 else
610 mc_lseek (file, 0, SEEK_SET);
612 if (vertical_insertion)
613 blocklen = edit_insert_column_of_text_from_file (edit, file);
614 else
615 while ((blocklen = mc_read (file, (char *) buf, TEMP_BUF_LEN)) > 0)
616 for (i = 0; i < blocklen; i++)
617 edit_insert (edit, buf[i]);
618 edit_cursor_move (edit, current - edit->curs1);
619 g_free (buf);
620 mc_close (file);
621 if (blocklen != 0)
622 return 0;
624 return 1;
627 /* Open file and create it if necessary. Return 0 for success, 1 for error. */
628 static int
629 check_file_access (WEdit * edit, const char *filename, struct stat *st)
631 int file;
632 gchar *errmsg = NULL;
634 /* Try opening an existing file */
635 file = mc_open (filename, O_NONBLOCK | O_RDONLY | O_BINARY, 0666);
637 if (file < 0)
640 * Try creating the file. O_EXCL prevents following broken links
641 * and opening existing files.
643 file = mc_open (filename, O_NONBLOCK | O_RDONLY | O_BINARY | O_CREAT | O_EXCL, 0666);
644 if (file < 0)
646 errmsg = g_strdup_printf (_("Cannot open %s for reading"), filename);
647 goto cleanup;
649 else
651 /* New file, delete it if it's not modified or saved */
652 edit->delete_file = 1;
656 /* Check what we have opened */
657 if (mc_fstat (file, st) < 0)
659 errmsg = g_strdup_printf (_("Cannot get size/permissions for %s"), filename);
660 goto cleanup;
663 /* We want to open regular files only */
664 if (!S_ISREG (st->st_mode))
666 errmsg = g_strdup_printf (_("\"%s\" is not a regular file"), filename);
667 goto cleanup;
671 * Don't delete non-empty files.
672 * O_EXCL should prevent it, but let's be on the safe side.
674 if (st->st_size > 0)
675 edit->delete_file = 0;
677 if (st->st_size >= SIZE_LIMIT)
678 errmsg = g_strdup_printf (_("File \"%s\" is too large"), filename);
680 cleanup:
681 (void) mc_close (file);
683 if (errmsg != NULL)
685 edit_error_dialog (_("Error"), errmsg);
686 g_free (errmsg);
687 return 1;
689 return 0;
693 * Open the file and load it into the buffers, either directly or using
694 * a filter. Return 0 on success, 1 on error.
696 * Fast loading (edit_load_file_fast) is used when the file size is
697 * known. In this case the data is read into the buffers by blocks.
698 * If the file size is not known, the data is loaded byte by byte in
699 * edit_insert_file.
701 static int
702 edit_load_file (WEdit * edit)
704 int fast_load = 1;
706 /* Cannot do fast load if a filter is used */
707 if (edit_find_filter (edit->filename) >= 0)
708 fast_load = 0;
711 * VFS may report file size incorrectly, and slow load is not a big
712 * deal considering overhead in VFS.
714 if (!vfs_file_is_local (edit->filename))
715 fast_load = 0;
718 * FIXME: line end translation should disable fast loading as well
719 * Consider doing fseek() to the end and ftell() for the real size.
722 if (*edit->filename)
724 /* If we are dealing with a real file, check that it exists */
725 if (check_file_access (edit, edit->filename, &edit->stat1))
726 return 1;
728 else
730 /* nothing to load */
731 fast_load = 0;
734 edit_init_buffers (edit);
736 if (fast_load)
738 edit->last_byte = edit->stat1.st_size;
739 edit_load_file_fast (edit, edit->filename);
740 /* If fast load was used, the number of lines wasn't calculated */
741 edit->total_lines = edit_count_lines (edit, 0, edit->last_byte);
743 else
745 #ifdef HAVE_CHARSET
746 const char *codepage_id;
747 #endif
748 edit->last_byte = 0;
749 if (*edit->filename)
751 edit->stack_disable = 1;
752 if (!edit_insert_file (edit, edit->filename))
754 edit_clean (edit);
755 return 1;
757 edit->stack_disable = 0;
760 #ifdef HAVE_CHARSET
761 codepage_id = get_codepage_id (source_codepage);
762 if (codepage_id)
763 edit->utf8 = str_isutf8 (codepage_id);
764 #endif
766 edit->lb = LB_ASIS;
767 return 0;
770 /* Restore saved cursor position in the file */
771 static void
772 edit_load_position (WEdit * edit)
774 char *filename;
775 long line, column;
776 off_t offset;
778 if (!edit->filename || !*edit->filename)
779 return;
781 filename = vfs_canon (edit->filename);
782 load_file_position (filename, &line, &column, &offset);
783 g_free (filename);
785 if (line > 0)
787 edit_move_to_line (edit, line - 1);
788 edit->prev_col = column;
790 else if (offset > 0)
792 edit_cursor_move (edit, offset);
793 line = edit->curs_line;
795 edit_move_to_prev_col (edit, edit_bol (edit, edit->curs1));
796 edit_move_display (edit, line - (edit->num_widget_lines / 2));
799 /* Save cursor position in the file */
800 static void
801 edit_save_position (WEdit * edit)
803 char *filename;
805 if (!edit->filename || !*edit->filename)
806 return;
808 filename = vfs_canon (edit->filename);
809 save_file_position (filename, edit->curs_line + 1, edit->curs_col, edit->curs1);
810 g_free (filename);
813 /* Clean the WEdit stricture except the widget part */
814 static void
815 edit_purge_widget (WEdit * edit)
817 size_t len = sizeof (WEdit) - sizeof (Widget);
818 char *start = (char *) edit + sizeof (Widget);
819 memset (start, 0, len);
820 edit->macro_i = -1; /* not recording a macro */
823 static void
824 edit_set_keymap (void)
826 editor_map = default_editor_keymap;
827 if (editor_keymap && editor_keymap->len > 0)
828 editor_map = (global_keymap_t *) editor_keymap->data;
830 editor_x_map = default_editor_x_keymap;
831 if (editor_x_keymap && editor_x_keymap->len > 0)
832 editor_x_map = (global_keymap_t *) editor_x_keymap->data;
836 #define space_width 1
839 * Fill in the edit structure. Return NULL on failure. Pass edit as
840 * NULL to allocate a new structure.
842 * If line is 0, try to restore saved position. Otherwise put the
843 * cursor on that line and show it in the middle of the screen.
845 WEdit *
846 edit_init (WEdit * edit, int lines, int columns, const char *filename, long line)
848 int to_free = 0;
849 option_auto_syntax = 1; /* Resetting to auto on every invokation */
850 if (option_line_state)
852 option_line_state_width = LINE_STATE_WIDTH;
854 else
856 option_line_state_width = 0;
858 if (!edit)
860 #ifdef ENABLE_NLS
862 * Expand option_whole_chars_search by national letters using
863 * current locale
866 static char option_whole_chars_search_buf[256];
868 if (option_whole_chars_search_buf != option_whole_chars_search)
870 size_t i;
871 size_t len = str_term_width1 (option_whole_chars_search);
873 strcpy (option_whole_chars_search_buf, option_whole_chars_search);
875 for (i = 1; i <= sizeof (option_whole_chars_search_buf); i++)
877 if (g_ascii_islower ((gchar) i) && !strchr (option_whole_chars_search, i))
879 option_whole_chars_search_buf[len++] = i;
883 option_whole_chars_search_buf[len] = 0;
884 option_whole_chars_search = option_whole_chars_search_buf;
886 #endif /* ENABLE_NLS */
887 edit = g_malloc0 (sizeof (WEdit));
888 edit->search = NULL;
889 to_free = 1;
891 edit_purge_widget (edit);
892 edit->num_widget_lines = lines;
893 edit->over_col = 0;
894 edit->num_widget_columns = columns;
895 edit->stat1.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
896 edit->stat1.st_uid = getuid ();
897 edit->stat1.st_gid = getgid ();
898 edit->stat1.st_mtime = 0;
899 edit->bracket = -1;
900 edit->force |= REDRAW_PAGE;
901 edit_set_filename (edit, filename);
902 edit->stack_size = START_STACK_SIZE;
903 edit->stack_size_mask = START_STACK_SIZE - 1;
904 edit->undo_stack = g_malloc0 ((edit->stack_size + 10) * sizeof (long));
906 edit->utf8 = 0;
907 edit->converter = str_cnv_from_term;
908 edit_set_codeset (edit);
910 if (edit_load_file (edit))
912 /* edit_load_file already gives an error message */
913 if (to_free)
914 g_free (edit);
915 return 0;
918 edit->loading_done = 1;
919 edit->modified = 0;
920 edit->locked = 0;
921 edit_load_syntax (edit, NULL, NULL);
923 int color;
924 edit_get_syntax_color (edit, -1, &color);
927 /* load saved cursor position */
928 if ((line == 0) && option_save_position)
930 edit_load_position (edit);
932 else
934 if (line <= 0)
935 line = 1;
936 edit_move_display (edit, line - 1);
937 edit_move_to_line (edit, line - 1);
940 edit_set_keymap ();
942 return edit;
945 /* Clear the edit struct, freeing everything in it. Return 1 on success */
947 edit_clean (WEdit * edit)
949 int j = 0;
951 if (!edit)
952 return 0;
954 /* a stale lock, remove it */
955 if (edit->locked)
956 edit->locked = edit_unlock_file (edit->filename);
958 /* save cursor position */
959 if (option_save_position)
960 edit_save_position (edit);
962 /* File specified on the mcedit command line and never saved */
963 if (edit->delete_file)
964 unlink (edit->filename);
966 edit_free_syntax_rules (edit);
967 book_mark_flush (edit, -1);
968 for (; j <= MAXBUFF; j++)
970 g_free (edit->buffers1[j]);
971 g_free (edit->buffers2[j]);
974 g_free (edit->undo_stack);
975 g_free (edit->filename);
976 g_free (edit->dir);
978 mc_search_free (edit->search);
979 edit->search = NULL;
981 if (edit->converter != str_cnv_from_term)
982 str_close_conv (edit->converter);
984 edit_purge_widget (edit);
986 return 1;
989 /* returns 1 on success */
991 edit_renew (WEdit * edit)
993 int lines = edit->num_widget_lines;
994 int columns = edit->num_widget_columns;
996 edit_clean (edit);
997 return (edit_init (edit, lines, columns, "", 0) != NULL);
1001 * Load a new file into the editor. If it fails, preserve the old file.
1002 * To do it, allocate a new widget, initialize it and, if the new file
1003 * was loaded, copy the data to the old widget.
1004 * Return 1 on success, 0 on failure.
1007 edit_reload (WEdit * edit, const char *filename)
1009 WEdit *e;
1010 int lines = edit->num_widget_lines;
1011 int columns = edit->num_widget_columns;
1013 e = g_malloc0 (sizeof (WEdit));
1014 e->widget = edit->widget;
1015 if (!edit_init (e, lines, columns, filename, 0))
1017 g_free (e);
1018 return 0;
1020 edit_clean (edit);
1021 memcpy (edit, e, sizeof (WEdit));
1022 g_free (e);
1023 return 1;
1027 * Load a new file into the editor and set line. If it fails, preserve the old file.
1028 * To do it, allocate a new widget, initialize it and, if the new file
1029 * was loaded, copy the data to the old widget.
1030 * Return 1 on success, 0 on failure.
1033 edit_reload_line (WEdit * edit, const char *filename, long line)
1035 WEdit *e;
1036 int lines = edit->num_widget_lines;
1037 int columns = edit->num_widget_columns;
1039 e = g_malloc0 (sizeof (WEdit));
1040 e->widget = edit->widget;
1041 if (!edit_init (e, lines, columns, filename, line))
1043 g_free (e);
1044 return 0;
1046 edit_clean (edit);
1047 memcpy (edit, e, sizeof (WEdit));
1048 g_free (e);
1049 return 1;
1052 void
1053 edit_set_codeset (WEdit *edit)
1055 #ifdef HAVE_CHARSET
1056 const char *cp_id;
1058 cp_id = get_codepage_id (source_codepage >= 0 ? source_codepage : display_codepage);
1060 if (cp_id != NULL)
1062 GIConv conv;
1063 conv = str_crt_conv_from (cp_id);
1064 if (conv != INVALID_CONV)
1066 if (edit->converter != str_cnv_from_term)
1067 str_close_conv (edit->converter);
1068 edit->converter = conv;
1072 if (cp_id != NULL)
1073 edit->utf8 = str_isutf8 (cp_id);
1074 #else
1075 (void) edit;
1076 #endif
1081 Recording stack for undo:
1082 The following is an implementation of a compressed stack. Identical
1083 pushes are recorded by a negative prefix indicating the number of times the
1084 same char was pushed. This saves space for repeated curs-left or curs-right
1085 delete etc.
1089 pushed: stored:
1093 b -3
1095 c --> -4
1101 If the stack long int is 0-255 it represents a normal insert (from a backspace),
1102 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
1103 of the cursor functions #define'd in edit-impl.h. 1000 through 700'000'000 is to
1104 set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
1105 position.
1107 The only way the cursor moves or the buffer is changed is through the routines:
1108 insert, backspace, insert_ahead, delete, and cursor_move.
1109 These record the reverse undo movements onto the stack each time they are
1110 called.
1112 Each key press results in a set of actions (insert; delete ...). So each time
1113 a key is pressed the current position of start_display is pushed as
1114 KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
1115 over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
1116 tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
1120 void
1121 edit_push_action (WEdit * edit, long c, ...)
1123 unsigned long sp = edit->stack_pointer;
1124 unsigned long spm1;
1125 long *t;
1127 /* first enlarge the stack if necessary */
1128 if (sp > edit->stack_size - 10)
1129 { /* say */
1130 if (option_max_undo < 256)
1131 option_max_undo = 256;
1132 if (edit->stack_size < (unsigned long) option_max_undo)
1134 t = g_realloc (edit->undo_stack, (edit->stack_size * 2 + 10) * sizeof (long));
1135 if (t)
1137 edit->undo_stack = t;
1138 edit->stack_size <<= 1;
1139 edit->stack_size_mask = edit->stack_size - 1;
1143 spm1 = (edit->stack_pointer - 1) & edit->stack_size_mask;
1144 if (edit->stack_disable)
1145 return;
1147 #ifdef FAST_MOVE_CURSOR
1148 if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS)
1150 va_list ap;
1151 edit->undo_stack[sp] = (c == CURS_LEFT_LOTS) ? CURS_LEFT : CURS_RIGHT;
1152 edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
1153 va_start (ap, c);
1154 c = -(va_arg (ap, int));
1155 va_end (ap);
1157 else
1158 #endif /* ! FAST_MOVE_CURSOR */
1159 if (edit->stack_bottom != sp
1160 && spm1 != edit->stack_bottom
1161 && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom)
1163 int d;
1164 if (edit->undo_stack[spm1] < 0)
1166 d = edit->undo_stack[(sp - 2) & edit->stack_size_mask];
1167 if (d == c)
1169 if (edit->undo_stack[spm1] > -1000000000)
1171 if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
1172 edit->undo_stack[spm1]--;
1173 return;
1176 /* #define NO_STACK_CURSMOVE_ANIHILATION */
1177 #ifndef NO_STACK_CURSMOVE_ANIHILATION
1178 else if ((c == CURS_LEFT && d == CURS_RIGHT) || (c == CURS_RIGHT && d == CURS_LEFT))
1179 { /* a left then a right anihilate each other */
1180 if (edit->undo_stack[spm1] == -2)
1181 edit->stack_pointer = spm1;
1182 else
1183 edit->undo_stack[spm1]++;
1184 return;
1186 #endif
1188 else
1190 d = edit->undo_stack[spm1];
1191 if (d == c)
1193 if (c >= KEY_PRESS)
1194 return; /* --> no need to push multiple do-nothings */
1195 edit->undo_stack[sp] = -2;
1196 goto check_bottom;
1198 #ifndef NO_STACK_CURSMOVE_ANIHILATION
1199 else if ((c == CURS_LEFT && d == CURS_RIGHT) || (c == CURS_RIGHT && d == CURS_LEFT))
1200 { /* a left then a right anihilate each other */
1201 edit->stack_pointer = spm1;
1202 return;
1204 #endif
1207 edit->undo_stack[sp] = c;
1209 check_bottom:
1210 edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
1212 /* if the sp wraps round and catches the stack_bottom then erase
1213 * the first set of actions on the stack to make space - by moving
1214 * stack_bottom forward one "key press" */
1215 c = (edit->stack_pointer + 2) & edit->stack_size_mask;
1216 if ((unsigned long) c == edit->stack_bottom ||
1217 (((unsigned long) c + 1) & edit->stack_size_mask) == edit->stack_bottom)
1220 edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask;
1222 while (edit->undo_stack[edit->stack_bottom] < KEY_PRESS
1223 && edit->stack_bottom != edit->stack_pointer);
1225 /*If a single key produced enough pushes to wrap all the way round then we would notice that the [stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */
1226 if (edit->stack_pointer != edit->stack_bottom
1227 && edit->undo_stack[edit->stack_bottom] < KEY_PRESS)
1228 edit->stack_bottom = edit->stack_pointer = 0;
1232 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
1233 then the file should be as it was when he loaded up. Then set edit->modified to 0.
1235 static long
1236 pop_action (WEdit * edit)
1238 long c;
1239 unsigned long sp = edit->stack_pointer;
1241 if (sp == edit->stack_bottom)
1242 return STACK_BOTTOM;
1244 sp = (sp - 1) & edit->stack_size_mask;
1245 c = edit->undo_stack[sp];
1246 if (c >= 0)
1248 /* edit->undo_stack[sp] = '@'; */
1249 edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask;
1250 return c;
1253 if (sp == edit->stack_bottom)
1254 return STACK_BOTTOM;
1256 c = edit->undo_stack[(sp - 1) & edit->stack_size_mask];
1257 if (edit->undo_stack[sp] == -2)
1259 /* edit->undo_stack[sp] = '@'; */
1260 edit->stack_pointer = sp;
1262 else
1263 edit->undo_stack[sp]++;
1265 return c;
1268 /* is called whenever a modification is made by one of the four routines below */
1269 static void
1270 edit_modification (WEdit * edit)
1272 edit->caches_valid = 0;
1273 edit->screen_modified = 1;
1275 /* raise lock when file modified */
1276 if (!edit->modified && !edit->delete_file)
1277 edit->locked = edit_lock_file (edit->filename);
1278 edit->modified = 1;
1282 Basic low level single character buffer alterations and movements at the cursor.
1283 Returns char passed over, inserted or removed.
1286 void
1287 edit_insert (WEdit * edit, int c)
1289 /* check if file has grown to large */
1290 if (edit->last_byte >= SIZE_LIMIT)
1291 return;
1293 /* first we must update the position of the display window */
1294 if (edit->curs1 < edit->start_display)
1296 edit->start_display++;
1297 if (c == '\n')
1298 edit->start_line++;
1301 /* Mark file as modified, unless the file hasn't been fully loaded */
1302 if (edit->loading_done)
1304 edit_modification (edit);
1307 /* now we must update some info on the file and check if a redraw is required */
1308 if (c == '\n')
1310 if (edit->book_mark)
1311 book_mark_inc (edit, edit->curs_line);
1312 edit->curs_line++;
1313 edit->total_lines++;
1314 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
1317 /* save the reverse command onto the undo stack */
1318 edit_push_action (edit, BACKSPACE);
1320 /* update markers */
1321 edit->mark1 += (edit->mark1 > edit->curs1);
1322 edit->mark2 += (edit->mark2 > edit->curs1);
1323 edit->last_get_rule += (edit->last_get_rule > edit->curs1);
1325 /* add a new buffer if we've reached the end of the last one */
1326 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
1327 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
1329 /* perform the insertion */
1330 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE]
1331 = (unsigned char) c;
1333 /* update file length */
1334 edit->last_byte++;
1336 /* update cursor position */
1337 edit->curs1++;
1340 static void
1341 edit_insert_over (WEdit * edit)
1343 int i;
1345 for (i = 0; i < edit->over_col; i++)
1347 edit_insert (edit, ' ');
1349 edit->over_col = 0;
1352 /* same as edit_insert and move left */
1353 void
1354 edit_insert_ahead (WEdit * edit, int c)
1356 if (edit->last_byte >= SIZE_LIMIT)
1357 return;
1359 if (edit->curs1 < edit->start_display)
1361 edit->start_display++;
1362 if (c == '\n')
1363 edit->start_line++;
1365 edit_modification (edit);
1366 if (c == '\n')
1368 if (edit->book_mark)
1369 book_mark_inc (edit, edit->curs_line);
1370 edit->total_lines++;
1371 edit->force |= REDRAW_AFTER_CURSOR;
1373 edit_push_action (edit, DELCHAR);
1375 edit->mark1 += (edit->mark1 >= edit->curs1);
1376 edit->mark2 += (edit->mark2 >= edit->curs1);
1377 edit->last_get_rule += (edit->last_get_rule >= edit->curs1);
1379 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
1380 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
1381 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]
1382 [EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
1384 edit->last_byte++;
1385 edit->curs2++;
1390 edit_delete (WEdit * edit, const int byte_delete)
1392 int p = 0;
1393 int cw = 1;
1394 int i;
1396 if (!edit->curs2)
1397 return 0;
1399 edit->mark1 -= (edit->mark1 > edit->curs1);
1400 edit->mark2 -= (edit->mark2 > edit->curs1);
1401 edit->last_get_rule -= (edit->last_get_rule > edit->curs1);
1403 cw = 1;
1404 /* if byte_delete = 1 then delete only one byte not multibyte char */
1405 if (edit->utf8 && byte_delete == 0)
1407 edit_get_utf (edit, edit->curs1, &cw);
1408 if (cw < 1)
1409 cw = 1;
1411 for (i = 1; i <= cw; i++)
1413 p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE -
1414 ((edit->curs2 -
1415 1) & M_EDIT_BUF_SIZE) - 1];
1417 if (!(edit->curs2 & M_EDIT_BUF_SIZE))
1419 g_free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
1420 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL;
1422 edit->last_byte--;
1423 edit->curs2--;
1424 edit_push_action (edit, p + 256);
1427 edit_modification (edit);
1428 if (p == '\n')
1430 if (edit->book_mark)
1431 book_mark_dec (edit, edit->curs_line);
1432 edit->total_lines--;
1433 edit->force |= REDRAW_AFTER_CURSOR;
1435 if (edit->curs1 < edit->start_display)
1437 edit->start_display--;
1438 if (p == '\n')
1439 edit->start_line--;
1442 return p;
1446 static int
1447 edit_backspace (WEdit * edit, const int byte_delete)
1449 int p = 0;
1450 int cw = 1;
1451 int i;
1453 if (!edit->curs1)
1454 return 0;
1456 edit->mark1 -= (edit->mark1 >= edit->curs1);
1457 edit->mark2 -= (edit->mark2 >= edit->curs1);
1458 edit->last_get_rule -= (edit->last_get_rule >= edit->curs1);
1460 cw = 1;
1461 if (edit->utf8 && byte_delete == 0)
1463 edit_get_prev_utf (edit, edit->curs1, &cw);
1464 if (cw < 1)
1465 cw = 1;
1467 for (i = 1; i <= cw; i++)
1469 p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] +
1470 ((edit->curs1 - 1) & M_EDIT_BUF_SIZE));
1471 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE))
1473 g_free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
1474 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
1476 edit->last_byte--;
1477 edit->curs1--;
1478 edit_push_action (edit, p);
1480 edit_modification (edit);
1481 if (p == '\n')
1483 if (edit->book_mark)
1484 book_mark_dec (edit, edit->curs_line);
1485 edit->curs_line--;
1486 edit->total_lines--;
1487 edit->force |= REDRAW_AFTER_CURSOR;
1490 if (edit->curs1 < edit->start_display)
1492 edit->start_display--;
1493 if (p == '\n')
1494 edit->start_line--;
1497 return p;
1500 #ifdef FAST_MOVE_CURSOR
1502 static void
1503 memqcpy (WEdit * edit, unsigned char *dest, unsigned char *src, int n)
1505 unsigned long next;
1506 while ((next = (unsigned long) memccpy (dest, src, '\n', n)))
1508 edit->curs_line--;
1509 next -= (unsigned long) dest;
1510 n -= next;
1511 src += next;
1512 dest += next;
1517 edit_move_backward_lots (WEdit * edit, long increment)
1519 int r, s, t;
1520 unsigned char *p = NULL;
1522 if (increment > edit->curs1)
1523 increment = edit->curs1;
1524 if (increment <= 0)
1525 return -1;
1526 edit_push_action (edit, CURS_RIGHT_LOTS, increment);
1528 t = r = EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
1529 if (r > increment)
1530 r = increment;
1531 s = edit->curs1 & M_EDIT_BUF_SIZE;
1533 if (s > r)
1535 memqcpy (edit,
1536 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
1537 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - r, r);
1539 else
1541 if (s != 0)
1543 memqcpy (edit,
1544 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t -
1545 s, edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE], s);
1546 p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
1547 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
1549 memqcpy (edit,
1550 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
1551 edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] +
1552 EDIT_BUF_SIZE - (r - s), r - s);
1554 increment -= r;
1555 edit->curs1 -= r;
1556 edit->curs2 += r;
1557 if (!(edit->curs2 & M_EDIT_BUF_SIZE))
1559 if (p)
1560 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
1561 else
1562 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
1564 else
1566 g_free (p);
1569 s = edit->curs1 & M_EDIT_BUF_SIZE;
1570 while (increment)
1572 p = 0;
1573 r = EDIT_BUF_SIZE;
1574 if (r > increment)
1575 r = increment;
1576 t = s;
1577 if (r < t)
1578 t = r;
1579 memqcpy (edit,
1580 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] +
1581 EDIT_BUF_SIZE - t, edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - t, t);
1582 if (r >= s)
1584 if (t)
1586 p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
1587 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
1589 memqcpy (edit,
1590 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] +
1591 EDIT_BUF_SIZE - r,
1592 edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] +
1593 EDIT_BUF_SIZE - (r - s), r - s);
1595 increment -= r;
1596 edit->curs1 -= r;
1597 edit->curs2 += r;
1598 if (!(edit->curs2 & M_EDIT_BUF_SIZE))
1600 if (p)
1601 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
1602 else
1603 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
1605 else
1606 g_free (p);
1608 return edit_get_byte (edit, edit->curs1);
1611 #endif /* ! FAST_MOVE_CURSOR */
1613 /* moves the cursor right or left: increment positive or negative respectively */
1614 void
1615 edit_cursor_move (WEdit * edit, long increment)
1617 /* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
1618 int c;
1619 #ifdef FAST_MOVE_CURSOR
1620 if (increment < -256)
1622 edit->force |= REDRAW_PAGE;
1623 edit_move_backward_lots (edit, -increment);
1624 return;
1626 #endif /* ! FAST_MOVE_CURSOR */
1628 if (increment < 0)
1630 for (; increment < 0; increment++)
1632 if (!edit->curs1)
1633 return;
1635 edit_push_action (edit, CURS_RIGHT);
1637 c = edit_get_byte (edit, edit->curs1 - 1);
1638 if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
1639 edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
1640 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE -
1641 (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
1642 edit->curs2++;
1643 c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 -
1644 1) & M_EDIT_BUF_SIZE];
1645 if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE))
1647 g_free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
1648 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
1650 edit->curs1--;
1651 if (c == '\n')
1653 edit->curs_line--;
1654 edit->force |= REDRAW_LINE_BELOW;
1659 else if (increment > 0)
1661 for (; increment > 0; increment--)
1663 if (!edit->curs2)
1664 return;
1666 edit_push_action (edit, CURS_LEFT);
1668 c = edit_get_byte (edit, edit->curs1);
1669 if (!(edit->curs1 & M_EDIT_BUF_SIZE))
1670 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = g_malloc0 (EDIT_BUF_SIZE);
1671 edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c;
1672 edit->curs1++;
1673 c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE -
1674 ((edit->curs2 -
1675 1) & M_EDIT_BUF_SIZE) - 1];
1676 if (!(edit->curs2 & M_EDIT_BUF_SIZE))
1678 g_free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
1679 edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = 0;
1681 edit->curs2--;
1682 if (c == '\n')
1684 edit->curs_line++;
1685 edit->force |= REDRAW_LINE_ABOVE;
1691 /* These functions return positions relative to lines */
1693 /* returns index of last char on line + 1 */
1694 long
1695 edit_eol (WEdit * edit, long current)
1697 if (current >= edit->last_byte)
1698 return edit->last_byte;
1700 for (;; current++)
1701 if (edit_get_byte (edit, current) == '\n')
1702 break;
1703 return current;
1706 /* returns index of first char on line */
1707 long
1708 edit_bol (WEdit * edit, long current)
1710 if (current <= 0)
1711 return 0;
1713 for (;; current--)
1714 if (edit_get_byte (edit, current - 1) == '\n')
1715 break;
1716 return current;
1720 long
1721 edit_count_lines (WEdit * edit, long current, long upto)
1723 long lines = 0;
1724 if (upto > edit->last_byte)
1725 upto = edit->last_byte;
1726 if (current < 0)
1727 current = 0;
1728 while (current < upto)
1729 if (edit_get_byte (edit, current++) == '\n')
1730 lines++;
1731 return lines;
1735 /* If lines is zero this returns the count of lines from current to upto. */
1736 /* If upto is zero returns index of lines forward current. */
1737 long
1738 edit_move_forward (WEdit * edit, long current, long lines, long upto)
1740 if (upto)
1742 return edit_count_lines (edit, current, upto);
1744 else
1746 long next;
1747 if (lines < 0)
1748 lines = 0;
1749 while (lines--)
1751 next = edit_eol (edit, current) + 1;
1752 if (next > edit->last_byte)
1753 break;
1754 else
1755 current = next;
1757 return current;
1762 /* Returns offset of 'lines' lines up from current */
1763 long
1764 edit_move_backward (WEdit * edit, long current, long lines)
1766 if (lines < 0)
1767 lines = 0;
1768 current = edit_bol (edit, current);
1769 while ((lines--) && current != 0)
1770 current = edit_bol (edit, current - 1);
1771 return current;
1774 /* If cols is zero this returns the count of columns from current to upto. */
1775 /* If upto is zero returns index of cols across from current. */
1776 long
1777 edit_move_forward3 (WEdit * edit, long current, int cols, long upto)
1779 long p, q;
1780 int col;
1782 if (upto)
1784 q = upto;
1785 cols = -10;
1787 else
1788 q = edit->last_byte + 2;
1790 for (col = 0, p = current; p < q; p++)
1792 int c, orig_c;
1793 int utf_ch = 0;
1794 #ifdef HAVE_CHARSET
1795 int cw = 1;
1796 #endif
1797 if (cols != -10)
1799 if (col == cols)
1800 return p;
1801 if (col > cols)
1802 return p - 1;
1804 orig_c = c = edit_get_byte (edit, p);
1805 #ifdef HAVE_CHARSET
1806 if (edit->utf8)
1808 utf_ch = edit_get_utf (edit, p, &cw);
1809 if (utf8_display)
1811 if (cw > 1)
1812 col -= cw - 1;
1813 if (g_unichar_iswide (utf_ch))
1814 col++;
1816 else if (cw > 1 && g_unichar_isprint (utf_ch))
1817 col -= cw - 1;
1819 #endif
1820 c = convert_to_display_c (c);
1821 if (c == '\t')
1822 col += TAB_SIZE - col % TAB_SIZE;
1823 else if (c == '\n')
1825 if (upto)
1826 return col;
1827 else
1828 return p;
1830 else if ((c < 32 || c == 127) && (orig_c == c || (!utf8_display && !edit->utf8)))
1831 /* '\r' is shown as ^M, so we must advance 2 characters */
1832 /* Caret notation for control characters */
1833 col += 2;
1834 else
1835 col++;
1837 return col;
1840 /* returns the current column position of the cursor */
1842 edit_get_col (WEdit * edit)
1844 return edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
1848 /* Scrolling functions */
1850 void
1851 edit_update_curs_row (WEdit * edit)
1853 edit->curs_row = edit->curs_line - edit->start_line;
1856 void
1857 edit_update_curs_col (WEdit * edit)
1859 edit->curs_col = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
1863 edit_get_curs_col (const WEdit * edit)
1865 return edit->curs_col;
1868 /*moves the display start position up by i lines */
1869 void
1870 edit_scroll_upward (WEdit * edit, unsigned long i)
1872 unsigned long lines_above = edit->start_line;
1873 if (i > lines_above)
1874 i = lines_above;
1875 if (i)
1877 edit->start_line -= i;
1878 edit->start_display = edit_move_backward (edit, edit->start_display, i);
1879 edit->force |= REDRAW_PAGE;
1880 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1882 edit_update_curs_row (edit);
1886 /* returns 1 if could scroll, 0 otherwise */
1887 void
1888 edit_scroll_downward (WEdit * edit, int i)
1890 int lines_below;
1891 lines_below = edit->total_lines - edit->start_line - (edit->num_widget_lines - 1);
1892 if (lines_below > 0)
1894 if (i > lines_below)
1895 i = lines_below;
1896 edit->start_line += i;
1897 edit->start_display = edit_move_forward (edit, edit->start_display, i, 0);
1898 edit->force |= REDRAW_PAGE;
1899 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1901 edit_update_curs_row (edit);
1904 void
1905 edit_scroll_right (WEdit * edit, int i)
1907 edit->force |= REDRAW_PAGE;
1908 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1909 edit->start_col -= i;
1912 void
1913 edit_scroll_left (WEdit * edit, int i)
1915 if (edit->start_col)
1917 edit->start_col += i;
1918 if (edit->start_col > 0)
1919 edit->start_col = 0;
1920 edit->force |= REDRAW_PAGE;
1921 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
1925 /* high level cursor movement commands */
1927 static int
1928 is_in_indent (WEdit * edit)
1930 long p = edit_bol (edit, edit->curs1);
1931 while (p < edit->curs1)
1932 if (!strchr (" \t", edit_get_byte (edit, p++)))
1933 return 0;
1934 return 1;
1937 static int left_of_four_spaces (WEdit * edit);
1939 void
1940 edit_move_to_prev_col (WEdit * edit, long p)
1942 int prev = edit->prev_col;
1943 int over = edit->over_col;
1944 edit_cursor_move (edit, edit_move_forward3 (edit, p, prev + edit->over_col, 0) - edit->curs1);
1946 if (option_cursor_beyond_eol)
1948 long line_len = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
1949 edit_eol (edit, edit->curs1));
1951 if (line_len < prev + edit->over_col)
1953 edit->over_col = prev + over - line_len;
1954 edit->prev_col = line_len;
1955 edit->curs_col = line_len;
1957 else
1959 edit->curs_col = prev + over;
1960 edit->prev_col = edit->curs_col;
1961 edit->over_col = 0;
1964 else
1966 edit->over_col = 0;
1967 if (is_in_indent (edit) && option_fake_half_tabs)
1969 edit_update_curs_col (edit);
1970 if (space_width)
1971 if (edit->curs_col % (HALF_TAB_SIZE * space_width))
1973 int q = edit->curs_col;
1974 edit->curs_col -= (edit->curs_col % (HALF_TAB_SIZE * space_width));
1975 p = edit_bol (edit, edit->curs1);
1976 edit_cursor_move (edit,
1977 edit_move_forward3 (edit, p, edit->curs_col,
1978 0) - edit->curs1);
1979 if (!left_of_four_spaces (edit))
1980 edit_cursor_move (edit, edit_move_forward3 (edit, p, q, 0) - edit->curs1);
1986 static int
1987 is_blank (WEdit * edit, long offset)
1989 long s, f;
1990 int c;
1991 s = edit_bol (edit, offset);
1992 f = edit_eol (edit, offset) - 1;
1993 while (s <= f)
1995 c = edit_get_byte (edit, s++);
1996 if (!isspace (c))
1997 return 0;
1999 return 1;
2003 /* returns the offset of line i */
2004 static long
2005 edit_find_line (WEdit * edit, int line)
2007 int i, j = 0;
2008 int m = 2000000000;
2009 if (!edit->caches_valid)
2011 for (i = 0; i < N_LINE_CACHES; i++)
2012 edit->line_numbers[i] = edit->line_offsets[i] = 0;
2013 /* three offsets that we *know* are line 0 at 0 and these two: */
2014 edit->line_numbers[1] = edit->curs_line;
2015 edit->line_offsets[1] = edit_bol (edit, edit->curs1);
2016 edit->line_numbers[2] = edit->total_lines;
2017 edit->line_offsets[2] = edit_bol (edit, edit->last_byte);
2018 edit->caches_valid = 1;
2020 if (line >= edit->total_lines)
2021 return edit->line_offsets[2];
2022 if (line <= 0)
2023 return 0;
2024 /* find the closest known point */
2025 for (i = 0; i < N_LINE_CACHES; i++)
2027 int n;
2028 n = abs (edit->line_numbers[i] - line);
2029 if (n < m)
2031 m = n;
2032 j = i;
2035 if (m == 0)
2036 return edit->line_offsets[j]; /* know the offset exactly */
2037 if (m == 1 && j >= 3)
2038 i = j; /* one line different - caller might be looping, so stay in this cache */
2039 else
2040 i = 3 + (rand () % (N_LINE_CACHES - 3));
2041 if (line > edit->line_numbers[j])
2042 edit->line_offsets[i] =
2043 edit_move_forward (edit, edit->line_offsets[j], line - edit->line_numbers[j], 0);
2044 else
2045 edit->line_offsets[i] =
2046 edit_move_backward (edit, edit->line_offsets[j], edit->line_numbers[j] - line);
2047 edit->line_numbers[i] = line;
2048 return edit->line_offsets[i];
2052 line_is_blank (WEdit * edit, long line)
2054 return is_blank (edit, edit_find_line (edit, line));
2057 /* moves up until a blank line is reached, or until just
2058 before a non-blank line is reached */
2059 static void
2060 edit_move_up_paragraph (WEdit * edit, int do_scroll)
2062 int i = 0;
2063 if (edit->curs_line > 1)
2065 if (line_is_blank (edit, edit->curs_line))
2067 if (line_is_blank (edit, edit->curs_line - 1))
2069 for (i = edit->curs_line - 1; i; i--)
2070 if (!line_is_blank (edit, i))
2072 i++;
2073 break;
2076 else
2078 for (i = edit->curs_line - 1; i; i--)
2079 if (line_is_blank (edit, i))
2080 break;
2083 else
2085 for (i = edit->curs_line - 1; i; i--)
2086 if (line_is_blank (edit, i))
2087 break;
2090 edit_move_up (edit, edit->curs_line - i, do_scroll);
2093 /* moves down until a blank line is reached, or until just
2094 before a non-blank line is reached */
2095 static void
2096 edit_move_down_paragraph (WEdit * edit, int do_scroll)
2098 int i;
2099 if (edit->curs_line >= edit->total_lines - 1)
2101 i = edit->total_lines;
2103 else
2105 if (line_is_blank (edit, edit->curs_line))
2107 if (line_is_blank (edit, edit->curs_line + 1))
2109 for (i = edit->curs_line + 1; i; i++)
2110 if (!line_is_blank (edit, i) || i > edit->total_lines)
2112 i--;
2113 break;
2116 else
2118 for (i = edit->curs_line + 1; i; i++)
2119 if (line_is_blank (edit, i) || i >= edit->total_lines)
2120 break;
2123 else
2125 for (i = edit->curs_line + 1; i; i++)
2126 if (line_is_blank (edit, i) || i >= edit->total_lines)
2127 break;
2130 edit_move_down (edit, i - edit->curs_line, do_scroll);
2133 static void
2134 edit_begin_page (WEdit * edit)
2136 edit_update_curs_row (edit);
2137 edit_move_up (edit, edit->curs_row, 0);
2140 static void
2141 edit_end_page (WEdit * edit)
2143 edit_update_curs_row (edit);
2144 edit_move_down (edit, edit->num_widget_lines - edit->curs_row - 1, 0);
2148 /* goto beginning of text */
2149 static void
2150 edit_move_to_top (WEdit * edit)
2152 if (edit->curs_line)
2154 edit_cursor_move (edit, -edit->curs1);
2155 edit_move_to_prev_col (edit, 0);
2156 edit->force |= REDRAW_PAGE;
2157 edit->search_start = 0;
2158 edit_update_curs_row (edit);
2163 /* goto end of text */
2164 static void
2165 edit_move_to_bottom (WEdit * edit)
2167 if (edit->curs_line < edit->total_lines)
2169 edit_move_down (edit, edit->total_lines - edit->curs_row, 0);
2170 edit->start_display = edit->last_byte;
2171 edit->start_line = edit->total_lines;
2172 edit_scroll_upward (edit, edit->num_widget_lines - 1);
2173 edit->force |= REDRAW_PAGE;
2177 /* goto beginning of line */
2178 static void
2179 edit_cursor_to_bol (WEdit * edit)
2181 edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
2182 edit->search_start = edit->curs1;
2183 edit->prev_col = edit_get_col (edit);
2184 edit->over_col = 0;
2187 /* goto end of line */
2188 static void
2189 edit_cursor_to_eol (WEdit * edit)
2191 edit_cursor_move (edit, edit_eol (edit, edit->curs1) - edit->curs1);
2192 edit->search_start = edit->curs1;
2193 edit->prev_col = edit_get_col (edit);
2194 edit->over_col = 0;
2197 /* move cursor to line 'line' */
2198 void
2199 edit_move_to_line (WEdit * e, long line)
2201 if (line < e->curs_line)
2202 edit_move_up (e, e->curs_line - line, 0);
2203 else
2204 edit_move_down (e, line - e->curs_line, 0);
2205 edit_scroll_screen_over_cursor (e);
2208 /* scroll window so that first visible line is 'line' */
2209 void
2210 edit_move_display (WEdit * e, long line)
2212 if (line < e->start_line)
2213 edit_scroll_upward (e, e->start_line - line);
2214 else
2215 edit_scroll_downward (e, line - e->start_line);
2218 /* save markers onto undo stack */
2219 void
2220 edit_push_markers (WEdit * edit)
2222 edit_push_action (edit, MARK_1 + edit->mark1);
2223 edit_push_action (edit, MARK_2 + edit->mark2);
2226 void
2227 edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2)
2229 edit->mark1 = m1;
2230 edit->mark2 = m2;
2231 edit->column1 = c1;
2232 edit->column2 = c2;
2236 /* highlight marker toggle */
2237 void
2238 edit_mark_cmd (WEdit * edit, int unmark)
2240 edit_push_markers (edit);
2241 if (unmark)
2243 edit_set_markers (edit, 0, 0, 0, 0);
2244 edit->force |= REDRAW_PAGE;
2246 else
2248 if (edit->mark2 >= 0)
2250 edit_set_markers (edit, edit->curs1, -1, edit->curs_col + edit->over_col,
2251 edit->curs_col + edit->over_col);
2252 edit->force |= REDRAW_PAGE;
2254 else
2255 edit_set_markers (edit, edit->mark1, edit->curs1, edit->column1,
2256 edit->curs_col + edit->over_col);
2260 static unsigned long
2261 my_type_of (int c)
2263 int x, r = 0;
2264 const char *p, *q;
2265 const char option_chars_move_whole_word[] =
2266 "!=&|<>^~ !:;, !'!`!.?!\"!( !) !Aa0 !+-*/= |<> ![ !] !\\#! ";
2268 if (!c)
2269 return 0;
2270 if (c == '!')
2272 if (*option_chars_move_whole_word == '!')
2273 return 2;
2274 return 0x80000000UL;
2276 if (g_ascii_isupper ((gchar) c))
2277 c = 'A';
2278 else if (g_ascii_islower ((gchar) c))
2279 c = 'a';
2280 else if (g_ascii_isalpha (c))
2281 c = 'a';
2282 else if (isdigit (c))
2283 c = '0';
2284 else if (isspace (c))
2285 c = ' ';
2286 q = strchr (option_chars_move_whole_word, c);
2287 if (!q)
2288 return 0xFFFFFFFFUL;
2291 for (x = 1, p = option_chars_move_whole_word; p < q; p++)
2292 if (*p == '!')
2293 x <<= 1;
2294 r |= x;
2296 while ((q = strchr (q + 1, c)));
2297 return r;
2300 static void
2301 edit_left_word_move (WEdit * edit, int s)
2303 for (;;)
2305 int c1, c2;
2306 if (column_highlighting
2307 && edit->mark1 != edit->mark2
2308 && edit->over_col == 0 && edit->curs1 == edit_bol (edit, edit->curs1))
2309 break;
2310 edit_cursor_move (edit, -1);
2311 if (!edit->curs1)
2312 break;
2313 c1 = edit_get_byte (edit, edit->curs1 - 1);
2314 c2 = edit_get_byte (edit, edit->curs1);
2315 if (!(my_type_of (c1) & my_type_of (c2)))
2316 break;
2317 if (isspace (c1) && !isspace (c2))
2318 break;
2319 if (s)
2320 if (!isspace (c1) && isspace (c2))
2321 break;
2325 static void
2326 edit_left_word_move_cmd (WEdit * edit)
2328 edit_left_word_move (edit, 0);
2329 edit->force |= REDRAW_PAGE;
2332 static void
2333 edit_right_word_move (WEdit * edit, int s)
2335 for (;;)
2337 int c1, c2;
2338 if (column_highlighting
2339 && edit->mark1 != edit->mark2
2340 && edit->over_col == 0 && edit->curs1 == edit_eol (edit, edit->curs1))
2341 break;
2342 edit_cursor_move (edit, 1);
2343 if (edit->curs1 >= edit->last_byte)
2344 break;
2345 c1 = edit_get_byte (edit, edit->curs1 - 1);
2346 c2 = edit_get_byte (edit, edit->curs1);
2347 if (!(my_type_of (c1) & my_type_of (c2)))
2348 break;
2349 if (isspace (c1) && !isspace (c2))
2350 break;
2351 if (s)
2352 if (!isspace (c1) && isspace (c2))
2353 break;
2357 static void
2358 edit_right_word_move_cmd (WEdit * edit)
2360 edit_right_word_move (edit, 0);
2361 edit->force |= REDRAW_PAGE;
2364 static void
2365 edit_right_char_move_cmd (WEdit * edit)
2367 int cw = 1;
2368 int c = 0;
2369 if (edit->utf8)
2371 c = edit_get_utf (edit, edit->curs1, &cw);
2372 if (cw < 1)
2373 cw = 1;
2375 else
2377 c = edit_get_byte (edit, edit->curs1);
2379 if (option_cursor_beyond_eol && c == '\n')
2381 edit->over_col++;
2383 else
2385 edit_cursor_move (edit, cw);
2389 static void
2390 edit_left_char_move_cmd (WEdit * edit)
2392 int cw = 1;
2393 if (column_highlighting
2394 && option_cursor_beyond_eol
2395 && edit->mark1 != edit->mark2
2396 && edit->over_col == 0 && edit->curs1 == edit_bol (edit, edit->curs1))
2397 return;
2398 if (edit->utf8)
2400 edit_get_prev_utf (edit, edit->curs1, &cw);
2401 if (cw < 1)
2402 cw = 1;
2404 if (option_cursor_beyond_eol && edit->over_col > 0)
2406 edit->over_col--;
2408 else
2410 edit_cursor_move (edit, -cw);
2414 /** Up or down cursor moving.
2415 direction = TRUE - move up
2416 = FALSE - move down
2418 static void
2419 edit_move_updown (WEdit * edit, unsigned long i, int do_scroll, gboolean direction)
2421 unsigned long p;
2422 unsigned long l = (direction) ? edit->curs_line : edit->total_lines - edit->curs_line;
2424 if (i > l)
2425 i = l;
2427 if (i == 0)
2428 return;
2430 if (i > 1)
2431 edit->force |= REDRAW_PAGE;
2432 if (do_scroll)
2434 if (direction)
2435 edit_scroll_upward (edit, i);
2436 else
2437 edit_scroll_downward (edit, i);
2439 p = edit_bol (edit, edit->curs1);
2441 p = (direction) ? edit_move_backward (edit, p, i) : edit_move_forward (edit, p, i, 0);
2443 edit_cursor_move (edit, p - edit->curs1);
2445 edit_move_to_prev_col (edit, p);
2447 /* search start of current multibyte char (like CJK) */
2448 if (edit->curs1 + 1 < edit->last_byte)
2450 edit_right_char_move_cmd (edit);
2451 edit_left_char_move_cmd (edit);
2454 edit->search_start = edit->curs1;
2455 edit->found_len = 0;
2458 static void
2459 edit_right_delete_word (WEdit * edit)
2461 int c1, c2;
2462 for (;;)
2464 if (edit->curs1 >= edit->last_byte)
2465 break;
2466 c1 = edit_delete (edit, 1);
2467 c2 = edit_get_byte (edit, edit->curs1);
2468 if ((isspace (c1) == 0) != (isspace (c2) == 0))
2469 break;
2470 if (!(my_type_of (c1) & my_type_of (c2)))
2471 break;
2475 static void
2476 edit_left_delete_word (WEdit * edit)
2478 int c1, c2;
2479 for (;;)
2481 if (edit->curs1 <= 0)
2482 break;
2483 c1 = edit_backspace (edit, 1);
2484 c2 = edit_get_byte (edit, edit->curs1 - 1);
2485 if ((isspace (c1) == 0) != (isspace (c2) == 0))
2486 break;
2487 if (!(my_type_of (c1) & my_type_of (c2)))
2488 break;
2493 the start column position is not recorded, and hence does not
2494 undo as it happed. But who would notice.
2496 static void
2497 edit_do_undo (WEdit * edit)
2499 long ac;
2500 long count = 0;
2502 edit->stack_disable = 1; /* don't record undo's onto undo stack! */
2503 edit->over_col = 0;
2504 while ((ac = pop_action (edit)) < KEY_PRESS)
2506 switch ((int) ac)
2508 case STACK_BOTTOM:
2509 goto done_undo;
2510 case CURS_RIGHT:
2511 edit_cursor_move (edit, 1);
2512 break;
2513 case CURS_LEFT:
2514 edit_cursor_move (edit, -1);
2515 break;
2516 case BACKSPACE:
2517 edit_backspace (edit, 1);
2518 break;
2519 case DELCHAR:
2520 edit_delete (edit, 1);
2521 break;
2522 case COLUMN_ON:
2523 column_highlighting = 1;
2524 break;
2525 case COLUMN_OFF:
2526 column_highlighting = 0;
2527 break;
2529 if (ac >= 256 && ac < 512)
2530 edit_insert_ahead (edit, ac - 256);
2531 if (ac >= 0 && ac < 256)
2532 edit_insert (edit, ac);
2534 if (ac >= MARK_1 - 2 && ac < MARK_2 - 2)
2536 edit->mark1 = ac - MARK_1;
2537 edit->column1 = edit_move_forward3 (edit, edit_bol (edit, edit->mark1), 0, edit->mark1);
2539 else if (ac >= MARK_2 - 2 && ac < KEY_PRESS)
2541 edit->mark2 = ac - MARK_2;
2542 edit->column2 = edit_move_forward3 (edit, edit_bol (edit, edit->mark2), 0, edit->mark2);
2544 if (count++)
2545 edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
2548 if (edit->start_display > ac - KEY_PRESS)
2550 edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display);
2551 edit->force |= REDRAW_PAGE;
2553 else if (edit->start_display < ac - KEY_PRESS)
2555 edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS);
2556 edit->force |= REDRAW_PAGE;
2558 edit->start_display = ac - KEY_PRESS; /* see push and pop above */
2559 edit_update_curs_row (edit);
2561 done_undo:;
2562 edit->stack_disable = 0;
2565 static void
2566 edit_delete_to_line_end (WEdit * edit)
2568 while (edit_get_byte (edit, edit->curs1) != '\n')
2570 if (!edit->curs2)
2571 break;
2572 edit_delete (edit, 1);
2576 static void
2577 edit_delete_to_line_begin (WEdit * edit)
2579 while (edit_get_byte (edit, edit->curs1 - 1) != '\n')
2581 if (!edit->curs1)
2582 break;
2583 edit_backspace (edit, 1);
2587 void
2588 edit_delete_line (WEdit * edit)
2591 * Delete right part of the line.
2592 * Note that edit_get_byte() returns '\n' when byte position is
2593 * beyond EOF.
2595 while (edit_get_byte (edit, edit->curs1) != '\n')
2597 (void) edit_delete (edit, 1);
2601 * Delete '\n' char.
2602 * Note that edit_delete() will not corrupt anything if called while
2603 * cursor position is EOF.
2605 (void) edit_delete (edit, 1);
2608 * Delete left part of the line.
2609 * Note, that edit_get_byte() returns '\n' when byte position is < 0.
2611 while (edit_get_byte (edit, edit->curs1 - 1) != '\n')
2613 (void) edit_backspace (edit, 1);
2617 void
2618 insert_spaces_tab (WEdit * edit, int half)
2620 int i;
2621 edit_update_curs_col (edit);
2622 i = ((edit->curs_col / (option_tab_spacing * space_width / (half + 1))) +
2623 1) * (option_tab_spacing * space_width / (half + 1)) - edit->curs_col;
2624 while (i > 0)
2626 edit_insert (edit, ' ');
2627 i -= space_width;
2631 static int
2632 is_aligned_on_a_tab (WEdit * edit)
2634 edit_update_curs_col (edit);
2635 return !((edit->curs_col % (TAB_SIZE * space_width))
2636 && edit->curs_col % (TAB_SIZE * space_width) != (HALF_TAB_SIZE * space_width));
2639 static int
2640 right_of_four_spaces (WEdit * edit)
2642 int i, ch = 0;
2643 for (i = 1; i <= HALF_TAB_SIZE; i++)
2644 ch |= edit_get_byte (edit, edit->curs1 - i);
2645 if (ch == ' ')
2646 return is_aligned_on_a_tab (edit);
2647 return 0;
2650 static int
2651 left_of_four_spaces (WEdit * edit)
2653 int i, ch = 0;
2654 for (i = 0; i < HALF_TAB_SIZE; i++)
2655 ch |= edit_get_byte (edit, edit->curs1 + i);
2656 if (ch == ' ')
2657 return is_aligned_on_a_tab (edit);
2658 return 0;
2662 edit_indent_width (WEdit * edit, long p)
2664 long q = p;
2665 while (strchr ("\t ", edit_get_byte (edit, q)) && q < edit->last_byte - 1) /* move to the end of the leading whitespace of the line */
2666 q++;
2667 return edit_move_forward3 (edit, p, 0, q); /* count the number of columns of indentation */
2670 void
2671 edit_insert_indent (WEdit * edit, int indent)
2673 if (!option_fill_tabs_with_spaces)
2675 while (indent >= TAB_SIZE)
2677 edit_insert (edit, '\t');
2678 indent -= TAB_SIZE;
2681 while (indent-- > 0)
2682 edit_insert (edit, ' ');
2685 static void
2686 edit_auto_indent (WEdit * edit)
2688 long p;
2689 char c;
2690 p = edit->curs1;
2691 /* use the previous line as a template */
2692 p = edit_move_backward (edit, p, 1);
2693 /* copy the leading whitespace of the line */
2694 for (;;)
2695 { /* no range check - the line _is_ \n-terminated */
2696 c = edit_get_byte (edit, p++);
2697 if (c != ' ' && c != '\t')
2698 break;
2699 edit_insert (edit, c);
2703 static inline void
2704 edit_double_newline (WEdit * edit)
2706 edit_insert (edit, '\n');
2707 if (edit_get_byte (edit, edit->curs1) == '\n')
2708 return;
2709 if (edit_get_byte (edit, edit->curs1 - 2) == '\n')
2710 return;
2711 edit->force |= REDRAW_PAGE;
2712 edit_insert (edit, '\n');
2715 static inline void
2716 edit_tab_cmd (WEdit * edit)
2718 int i;
2720 if (option_fake_half_tabs)
2722 if (is_in_indent (edit))
2724 /*insert a half tab (usually four spaces) unless there is a
2725 half tab already behind, then delete it and insert a
2726 full tab. */
2727 if (!option_fill_tabs_with_spaces && right_of_four_spaces (edit))
2729 for (i = 1; i <= HALF_TAB_SIZE; i++)
2730 edit_backspace (edit, 1);
2731 edit_insert (edit, '\t');
2733 else
2735 insert_spaces_tab (edit, 1);
2737 return;
2740 if (option_fill_tabs_with_spaces)
2742 insert_spaces_tab (edit, 0);
2744 else
2746 edit_insert (edit, '\t');
2750 static void
2751 check_and_wrap_line (WEdit * edit)
2753 int curs, c;
2754 if (!option_typewriter_wrap)
2755 return;
2756 edit_update_curs_col (edit);
2757 if (edit->curs_col < option_word_wrap_line_length)
2758 return;
2759 curs = edit->curs1;
2760 for (;;)
2762 curs--;
2763 c = edit_get_byte (edit, curs);
2764 if (c == '\n' || curs <= 0)
2766 edit_insert (edit, '\n');
2767 return;
2769 if (c == ' ' || c == '\t')
2771 int current = edit->curs1;
2772 edit_cursor_move (edit, curs - edit->curs1 + 1);
2773 edit_insert (edit, '\n');
2774 edit_cursor_move (edit, current - edit->curs1 + 1);
2775 return;
2780 static inline void edit_execute_macro (WEdit * edit, struct macro macro[], int n);
2782 void
2783 edit_push_key_press (WEdit * edit)
2785 edit_push_action (edit, KEY_PRESS + edit->start_display);
2786 if (edit->mark2 == -1)
2787 edit_push_action (edit, MARK_1 + edit->mark1);
2790 /* this find the matching bracket in either direction, and sets edit->bracket */
2791 static long
2792 edit_get_bracket (WEdit * edit, int in_screen, unsigned long furthest_bracket_search)
2794 const char *const b = "{}{[][()(", *p;
2795 int i = 1, a, inc = -1, c, d, n = 0;
2796 unsigned long j = 0;
2797 long q;
2798 edit_update_curs_row (edit);
2799 c = edit_get_byte (edit, edit->curs1);
2800 p = strchr (b, c);
2801 /* no limit */
2802 if (!furthest_bracket_search)
2803 furthest_bracket_search--;
2804 /* not on a bracket at all */
2805 if (!p)
2806 return -1;
2807 /* the matching bracket */
2808 d = p[1];
2809 /* going left or right? */
2810 if (strchr ("{[(", c))
2811 inc = 1;
2812 for (q = edit->curs1 + inc;; q += inc)
2814 /* out of buffer? */
2815 if (q >= edit->last_byte || q < 0)
2816 break;
2817 a = edit_get_byte (edit, q);
2818 /* don't want to eat CPU */
2819 if (j++ > furthest_bracket_search)
2820 break;
2821 /* out of screen? */
2822 if (in_screen)
2824 if (q < edit->start_display)
2825 break;
2826 /* count lines if searching downward */
2827 if (inc > 0 && a == '\n')
2828 if (n++ >= edit->num_widget_lines - edit->curs_row) /* out of screen */
2829 break;
2831 /* count bracket depth */
2832 i += (a == c) - (a == d);
2833 /* return if bracket depth is zero */
2834 if (!i)
2835 return q;
2837 /* no match */
2838 return -1;
2841 static long last_bracket = -1;
2843 void
2844 edit_find_bracket (WEdit * edit)
2846 edit->bracket = edit_get_bracket (edit, 1, 10000);
2847 if (last_bracket != edit->bracket)
2848 edit->force |= REDRAW_PAGE;
2849 last_bracket = edit->bracket;
2852 static inline void
2853 edit_goto_matching_bracket (WEdit * edit)
2855 long q;
2857 q = edit_get_bracket (edit, 0, 0);
2858 if (q >= 0)
2860 edit->bracket = edit->curs1;
2861 edit->force |= REDRAW_PAGE;
2862 edit_cursor_move (edit, q - edit->curs1);
2867 * This executes a command as though the user initiated it through a key
2868 * press. Callback with WIDGET_KEY as a message calls this after
2869 * translating the key press. This function can be used to pass any
2870 * command to the editor. Note that the screen wouldn't update
2871 * automatically. Either of command or char_for_insertion must be
2872 * passed as -1. Commands are executed, and char_for_insertion is
2873 * inserted at the cursor.
2875 void
2876 edit_execute_key_command (WEdit * edit, unsigned long command, int char_for_insertion)
2878 if (command == CK_Begin_Record_Macro)
2880 edit->macro_i = 0;
2881 edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
2882 return;
2884 if (command == CK_End_Record_Macro && edit->macro_i != -1)
2886 edit->force |= REDRAW_COMPLETELY;
2887 edit_save_macro_cmd (edit, edit->macro, edit->macro_i);
2888 edit->macro_i = -1;
2889 return;
2891 if (edit->macro_i >= 0 && edit->macro_i < MAX_MACRO_LENGTH - 1)
2893 edit->macro[edit->macro_i].command = command;
2894 edit->macro[edit->macro_i++].ch = char_for_insertion;
2896 /* record the beginning of a set of editing actions initiated by a key press */
2897 if (command != CK_Undo && command != CK_Ext_Mode)
2898 edit_push_key_press (edit);
2900 edit_execute_cmd (edit, command, char_for_insertion);
2901 if (column_highlighting)
2902 edit->force |= REDRAW_PAGE;
2905 static const char *const shell_cmd[] = SHELL_COMMANDS_i;
2908 This executes a command at a lower level than macro recording.
2909 It also does not push a key_press onto the undo stack. This means
2910 that if it is called many times, a single undo command will undo
2911 all of them. It also does not check for the Undo command.
2913 void
2914 edit_execute_cmd (WEdit * edit, unsigned long command, int char_for_insertion)
2916 edit->force |= REDRAW_LINE;
2918 /* The next key press will unhighlight the found string, so update
2919 * the whole page */
2920 if (edit->found_len || column_highlighting)
2921 edit->force |= REDRAW_PAGE;
2923 if (command / 100 == 6)
2924 { /* a highlight command like shift-arrow */
2925 column_highlighting = 0;
2926 if (!edit->highlight || (edit->mark2 != -1 && edit->mark1 != edit->mark2))
2928 edit_mark_cmd (edit, 1); /* clear */
2929 edit_mark_cmd (edit, 0); /* marking on */
2931 edit->highlight = 1;
2933 else
2934 { /* any other command */
2935 if (edit->highlight)
2936 edit_mark_cmd (edit, 0); /* clear */
2937 edit->highlight = 0;
2940 /* first check for undo */
2941 if (command == CK_Undo)
2943 edit_do_undo (edit);
2944 edit->found_len = 0;
2945 edit->prev_col = edit_get_col (edit);
2946 edit->search_start = edit->curs1;
2947 return;
2950 /* An ordinary key press */
2951 if (char_for_insertion >= 0)
2953 /* if non persistent selection and text selected */
2954 if (!option_persistent_selections)
2956 if (edit->mark1 != edit->mark2)
2957 edit_block_delete_cmd (edit);
2959 if (edit->overwrite)
2961 /* remove char only one time, after input first byte, multibyte chars */
2962 if ((!utf8_display || edit->charpoint == 0)
2963 && edit_get_byte (edit, edit->curs1) != '\n')
2964 edit_delete (edit, 0);
2966 if (option_cursor_beyond_eol && edit->over_col > 0)
2967 edit_insert_over (edit);
2968 #ifdef HAVE_CHARSET
2969 if (char_for_insertion > 255 && utf8_display == 0)
2971 unsigned char str[6 + 1];
2972 size_t i = 0;
2973 int res = g_unichar_to_utf8 (char_for_insertion, (char *) str);
2974 if (res == 0)
2976 str[0] = '.';
2977 str[1] = '\0';
2979 else
2981 str[res] = '\0';
2983 while (str[i] != 0 && i <= 6)
2985 char_for_insertion = str[i];
2986 edit_insert (edit, char_for_insertion);
2987 i++;
2990 else
2991 #endif
2992 edit_insert (edit, char_for_insertion);
2994 if (option_auto_para_formatting)
2996 format_paragraph (edit, 0);
2997 edit->force |= REDRAW_PAGE;
2999 else
3000 check_and_wrap_line (edit);
3001 edit->found_len = 0;
3002 edit->prev_col = edit_get_col (edit);
3003 edit->search_start = edit->curs1;
3004 edit_find_bracket (edit);
3005 return;
3008 switch (command)
3010 case CK_Begin_Page:
3011 case CK_End_Page:
3012 case CK_Begin_Page_Highlight:
3013 case CK_End_Page_Highlight:
3014 case CK_Word_Left:
3015 case CK_Word_Right:
3016 case CK_Up:
3017 case CK_Down:
3018 case CK_Left:
3019 case CK_Right:
3020 if (edit->mark2 >= 0)
3022 if (!option_persistent_selections)
3024 if (column_highlighting)
3025 edit_push_action (edit, COLUMN_ON);
3026 column_highlighting = 0;
3027 edit_mark_cmd (edit, 1);
3032 switch (command)
3034 case CK_Begin_Page:
3035 case CK_End_Page:
3036 case CK_Begin_Page_Highlight:
3037 case CK_End_Page_Highlight:
3038 case CK_Word_Left:
3039 case CK_Word_Right:
3040 case CK_Up:
3041 case CK_Down:
3042 case CK_Word_Left_Highlight:
3043 case CK_Word_Right_Highlight:
3044 case CK_Up_Highlight:
3045 case CK_Down_Highlight:
3046 case CK_Up_Alt_Highlight:
3047 case CK_Down_Alt_Highlight:
3048 if (edit->mark2 == -1)
3049 break; /*marking is following the cursor: may need to highlight a whole line */
3050 case CK_Left:
3051 case CK_Right:
3052 case CK_Left_Highlight:
3053 case CK_Right_Highlight:
3054 edit->force |= REDRAW_CHAR_ONLY;
3057 /* basic cursor key commands */
3058 switch (command)
3060 case CK_BackSpace:
3061 /* if non persistent selection and text selected */
3062 if (!option_persistent_selections)
3064 if (edit->mark1 != edit->mark2)
3066 edit_block_delete_cmd (edit);
3067 break;
3070 if (option_cursor_beyond_eol && edit->over_col > 0)
3072 edit->over_col--;
3073 break;
3075 if (option_backspace_through_tabs && is_in_indent (edit))
3077 while (edit_get_byte (edit, edit->curs1 - 1) != '\n' && edit->curs1 > 0)
3078 edit_backspace (edit, 1);
3079 break;
3081 else
3083 if (option_fake_half_tabs)
3085 int i;
3086 if (is_in_indent (edit) && right_of_four_spaces (edit))
3088 for (i = 0; i < HALF_TAB_SIZE; i++)
3089 edit_backspace (edit, 1);
3090 break;
3094 edit_backspace (edit, 0);
3095 break;
3096 case CK_Delete:
3097 /* if non persistent selection and text selected */
3098 if (!option_persistent_selections)
3100 if (edit->mark1 != edit->mark2)
3102 edit_block_delete_cmd (edit);
3103 break;
3107 if (option_cursor_beyond_eol && edit->over_col > 0)
3108 edit_insert_over (edit);
3110 if (option_fake_half_tabs)
3112 int i;
3113 if (is_in_indent (edit) && left_of_four_spaces (edit))
3115 for (i = 1; i <= HALF_TAB_SIZE; i++)
3116 edit_delete (edit, 1);
3117 break;
3120 edit_delete (edit, 0);
3121 break;
3122 case CK_Delete_Word_Left:
3123 edit->over_col = 0;
3124 edit_left_delete_word (edit);
3125 break;
3126 case CK_Delete_Word_Right:
3127 if (option_cursor_beyond_eol && edit->over_col > 0)
3128 edit_insert_over (edit);
3130 edit_right_delete_word (edit);
3131 break;
3132 case CK_Delete_Line:
3133 edit_delete_line (edit);
3134 break;
3135 case CK_Delete_To_Line_End:
3136 edit_delete_to_line_end (edit);
3137 break;
3138 case CK_Delete_To_Line_Begin:
3139 edit_delete_to_line_begin (edit);
3140 break;
3141 case CK_Enter:
3142 edit->over_col = 0;
3143 if (option_auto_para_formatting)
3145 edit_double_newline (edit);
3146 if (option_return_does_auto_indent)
3147 edit_auto_indent (edit);
3148 format_paragraph (edit, 0);
3150 else
3152 edit_insert (edit, '\n');
3153 if (option_return_does_auto_indent)
3155 edit_auto_indent (edit);
3158 break;
3159 case CK_Return:
3160 edit_insert (edit, '\n');
3161 break;
3163 case CK_Page_Up_Alt_Highlight:
3164 column_highlighting = 1;
3165 case CK_Page_Up:
3166 case CK_Page_Up_Highlight:
3167 edit_move_up (edit, edit->num_widget_lines - 1, 1);
3168 break;
3169 case CK_Page_Down_Alt_Highlight:
3170 column_highlighting = 1;
3171 case CK_Page_Down:
3172 case CK_Page_Down_Highlight:
3173 edit_move_down (edit, edit->num_widget_lines - 1, 1);
3174 break;
3175 case CK_Left_Alt_Highlight:
3176 column_highlighting = 1;
3177 case CK_Left:
3178 case CK_Left_Highlight:
3179 if (option_fake_half_tabs)
3181 if (is_in_indent (edit) && right_of_four_spaces (edit))
3183 if (option_cursor_beyond_eol && edit->over_col > 0)
3184 edit->over_col--;
3185 else
3186 edit_cursor_move (edit, -HALF_TAB_SIZE);
3187 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
3188 break;
3191 edit_left_char_move_cmd (edit);
3192 break;
3193 case CK_Right_Alt_Highlight:
3194 column_highlighting = 1;
3195 case CK_Right:
3196 case CK_Right_Highlight:
3197 if (option_fake_half_tabs)
3199 if (is_in_indent (edit) && left_of_four_spaces (edit))
3201 edit_cursor_move (edit, HALF_TAB_SIZE);
3202 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
3203 break;
3206 edit_right_char_move_cmd (edit);
3207 break;
3208 case CK_Begin_Page:
3209 case CK_Begin_Page_Highlight:
3210 edit_begin_page (edit);
3211 break;
3212 case CK_End_Page:
3213 case CK_End_Page_Highlight:
3214 edit_end_page (edit);
3215 break;
3216 case CK_Word_Left:
3217 case CK_Word_Left_Highlight:
3218 edit->over_col = 0;
3219 edit_left_word_move_cmd (edit);
3220 break;
3221 case CK_Word_Right:
3222 case CK_Word_Right_Highlight:
3223 edit->over_col = 0;
3224 edit_right_word_move_cmd (edit);
3225 break;
3226 case CK_Up_Alt_Highlight:
3227 column_highlighting = 1;
3228 case CK_Up:
3229 case CK_Up_Highlight:
3230 edit_move_up (edit, 1, 0);
3231 break;
3232 case CK_Down_Alt_Highlight:
3233 column_highlighting = 1;
3234 case CK_Down:
3235 case CK_Down_Highlight:
3236 edit_move_down (edit, 1, 0);
3237 break;
3238 case CK_Paragraph_Up_Alt_Highlight:
3239 column_highlighting = 1;
3240 case CK_Paragraph_Up:
3241 case CK_Paragraph_Up_Highlight:
3242 edit_move_up_paragraph (edit, 0);
3243 break;
3244 case CK_Paragraph_Down_Alt_Highlight:
3245 column_highlighting = 1;
3246 case CK_Paragraph_Down:
3247 case CK_Paragraph_Down_Highlight:
3248 edit_move_down_paragraph (edit, 0);
3249 break;
3250 case CK_Scroll_Up_Alt_Highlight:
3251 column_highlighting = 1;
3252 case CK_Scroll_Up:
3253 case CK_Scroll_Up_Highlight:
3254 edit_move_up (edit, 1, 1);
3255 break;
3256 case CK_Scroll_Down_Alt_Highlight:
3257 column_highlighting = 1;
3258 case CK_Scroll_Down:
3259 case CK_Scroll_Down_Highlight:
3260 edit_move_down (edit, 1, 1);
3261 break;
3262 case CK_Home:
3263 case CK_Home_Highlight:
3264 edit_cursor_to_bol (edit);
3265 break;
3266 case CK_End:
3267 case CK_End_Highlight:
3268 edit_cursor_to_eol (edit);
3269 break;
3270 case CK_Tab:
3271 /* if text marked shift block */
3272 if (edit->mark1 != edit->mark2 && !option_persistent_selections)
3274 if (edit->mark2 < 0)
3275 edit_mark_cmd (edit, 0);
3276 edit_move_block_to_right (edit);
3278 else
3280 if (option_cursor_beyond_eol)
3281 edit_insert_over (edit);
3282 edit_tab_cmd (edit);
3283 if (option_auto_para_formatting)
3285 format_paragraph (edit, 0);
3286 edit->force |= REDRAW_PAGE;
3288 else
3290 check_and_wrap_line (edit);
3293 break;
3295 case CK_Toggle_Insert:
3296 edit->overwrite = (edit->overwrite == 0);
3297 break;
3299 case CK_Mark:
3300 if (edit->mark2 >= 0)
3302 if (column_highlighting)
3303 edit_push_action (edit, COLUMN_ON);
3304 column_highlighting = 0;
3306 edit_mark_cmd (edit, 0);
3307 break;
3308 case CK_Column_Mark:
3309 if (!column_highlighting)
3310 edit_push_action (edit, COLUMN_OFF);
3311 column_highlighting = 1;
3312 edit_mark_cmd (edit, 0);
3313 break;
3314 case CK_Mark_All:
3315 edit_set_markers (edit, 0, edit->last_byte, 0, 0);
3316 edit->force |= REDRAW_PAGE;
3317 break;
3318 case CK_Unmark:
3319 if (column_highlighting)
3320 edit_push_action (edit, COLUMN_ON);
3321 column_highlighting = 0;
3322 edit_mark_cmd (edit, 1);
3323 break;
3325 case CK_Toggle_Line_State:
3326 option_line_state = !option_line_state;
3327 if (option_line_state)
3329 option_line_state_width = LINE_STATE_WIDTH;
3331 else
3333 option_line_state_width = 0;
3335 edit->force |= REDRAW_PAGE;
3336 break;
3338 case CK_Toggle_Show_Margin:
3339 show_right_margin = !show_right_margin;
3340 edit->force |= REDRAW_PAGE;
3341 break;
3343 case CK_Toggle_Bookmark:
3344 book_mark_clear (edit, edit->curs_line, BOOK_MARK_FOUND_COLOR);
3345 if (book_mark_query_color (edit, edit->curs_line, BOOK_MARK_COLOR))
3346 book_mark_clear (edit, edit->curs_line, BOOK_MARK_COLOR);
3347 else
3348 book_mark_insert (edit, edit->curs_line, BOOK_MARK_COLOR);
3349 break;
3350 case CK_Flush_Bookmarks:
3351 book_mark_flush (edit, BOOK_MARK_COLOR);
3352 book_mark_flush (edit, BOOK_MARK_FOUND_COLOR);
3353 edit->force |= REDRAW_PAGE;
3354 break;
3355 case CK_Next_Bookmark:
3356 if (edit->book_mark)
3358 struct _book_mark *p;
3359 p = (struct _book_mark *) book_mark_find (edit, edit->curs_line);
3360 if (p->next)
3362 p = p->next;
3363 if (p->line >= edit->start_line + edit->num_widget_lines
3364 || p->line < edit->start_line)
3365 edit_move_display (edit, p->line - edit->num_widget_lines / 2);
3366 edit_move_to_line (edit, p->line);
3369 break;
3370 case CK_Prev_Bookmark:
3371 if (edit->book_mark)
3373 struct _book_mark *p;
3374 p = (struct _book_mark *) book_mark_find (edit, edit->curs_line);
3375 while (p->line == edit->curs_line)
3376 if (p->prev)
3377 p = p->prev;
3378 if (p->line >= 0)
3380 if (p->line >= edit->start_line + edit->num_widget_lines
3381 || p->line < edit->start_line)
3382 edit_move_display (edit, p->line - edit->num_widget_lines / 2);
3383 edit_move_to_line (edit, p->line);
3386 break;
3388 case CK_Beginning_Of_Text:
3389 case CK_Beginning_Of_Text_Highlight:
3390 edit_move_to_top (edit);
3391 break;
3392 case CK_End_Of_Text:
3393 case CK_End_Of_Text_Highlight:
3394 edit_move_to_bottom (edit);
3395 break;
3397 case CK_Copy:
3398 if (option_cursor_beyond_eol && edit->over_col > 0)
3399 edit_insert_over (edit);
3400 edit_block_copy_cmd (edit);
3401 break;
3402 case CK_Remove:
3403 edit_block_delete_cmd (edit);
3404 break;
3405 case CK_Move:
3406 if (option_cursor_beyond_eol && edit->over_col > 0)
3407 edit_insert_over (edit);
3408 edit_block_move_cmd (edit);
3409 break;
3411 case CK_Shift_Block_Left:
3412 if (edit->mark1 != edit->mark2)
3413 edit_move_block_to_left (edit);
3414 break;
3415 case CK_Shift_Block_Right:
3416 if (edit->mark1 != edit->mark2)
3417 edit_move_block_to_right (edit);
3418 break;
3419 case CK_XStore:
3420 edit_copy_to_X_buf_cmd (edit);
3421 break;
3422 case CK_XCut:
3423 edit_cut_to_X_buf_cmd (edit);
3424 break;
3425 case CK_XPaste:
3426 /* if non persistent selection and text selected */
3427 if (!option_persistent_selections)
3429 if (edit->mark1 != edit->mark2)
3430 edit_block_delete_cmd (edit);
3432 if (option_cursor_beyond_eol && edit->over_col > 0)
3433 edit_insert_over (edit);
3434 edit_paste_from_X_buf_cmd (edit);
3435 break;
3436 case CK_Selection_History:
3437 edit_paste_from_history (edit);
3438 break;
3440 case CK_Save_As:
3441 edit_save_as_cmd (edit);
3442 break;
3443 case CK_Save:
3444 edit_save_confirm_cmd (edit);
3445 break;
3446 case CK_Load:
3447 edit_load_cmd (edit, EDIT_FILE_COMMON);
3448 break;
3449 case CK_Save_Block:
3450 edit_save_block_cmd (edit);
3451 break;
3452 case CK_Insert_File:
3453 edit_insert_file_cmd (edit);
3454 break;
3456 case CK_Load_Prev_File:
3457 edit_load_back_cmd (edit);
3458 break;
3459 case CK_Load_Next_File:
3460 edit_load_forward_cmd (edit);
3461 break;
3463 case CK_Load_Syntax_File:
3464 edit_load_cmd (edit, EDIT_FILE_SYNTAX);
3465 break;
3466 case CK_Choose_Syntax:
3467 edit_syntax_dialog (edit, edit->syntax_type);
3468 break;
3470 case CK_Load_Menu_File:
3471 edit_load_cmd (edit, EDIT_FILE_MENU);
3472 break;
3474 case CK_Toggle_Syntax:
3475 if ((option_syntax_highlighting ^= 1) == 1)
3476 edit_load_syntax (edit, NULL, edit->syntax_type);
3477 edit->force |= REDRAW_PAGE;
3478 break;
3480 case CK_Toggle_Tab_TWS:
3481 enable_show_tabs_tws ^= 1;
3482 edit->force |= REDRAW_PAGE;
3483 break;
3485 case CK_Find:
3486 edit_search_cmd (edit, 0);
3487 break;
3488 case CK_Find_Again:
3489 edit_search_cmd (edit, 1);
3490 break;
3491 case CK_Replace:
3492 edit_replace_cmd (edit, 0);
3493 break;
3494 case CK_Replace_Again:
3495 edit_replace_cmd (edit, 1);
3496 break;
3497 case CK_Complete_Word:
3498 /* if text marked shift block */
3499 if (edit->mark1 != edit->mark2 && !option_persistent_selections)
3501 edit_move_block_to_left (edit);
3503 else
3505 edit_complete_word_cmd (edit);
3507 break;
3508 case CK_Find_Definition:
3509 edit_get_match_keyword_cmd (edit);
3510 break;
3511 case CK_Quit:
3512 dlg_stop (edit->widget.parent);
3513 break;
3514 case CK_New:
3515 edit_new_cmd (edit);
3516 break;
3517 case CK_Help:
3518 edit_help_cmd (edit);
3519 break;
3520 case CK_Refresh:
3521 edit_refresh_cmd (edit);
3522 break;
3523 case CK_SaveSetupCmd:
3524 save_setup_cmd ();
3525 break;
3526 case CK_About:
3527 query_dialog (_("About"),
3528 _("\n Cooledit v3.11.5\n\n"
3529 " Copyright (C) 1996 the Free Software Foundation\n\n"
3530 " A user friendly text editor written\n"
3531 " for the Midnight Commander.\n"), D_NORMAL, 1, _("&OK"));
3532 break;
3533 case CK_LearnKeys:
3534 learn_keys ();
3535 break;
3536 case CK_Edit_Options:
3537 edit_options_dialog (edit);
3538 break;
3539 case CK_Edit_Save_Mode:
3540 menu_save_mode_cmd ();
3541 break;
3542 case CK_Date:
3544 char s[BUF_MEDIUM];
3545 /* fool gcc to prevent a Y2K warning */
3546 char time_format[] = "_c";
3547 time_format[0] = '%';
3549 FMT_LOCALTIME_CURRENT (s, sizeof (s), time_format);
3550 edit_print_string (edit, s);
3551 edit->force |= REDRAW_PAGE;
3552 break;
3554 break;
3555 case CK_Goto:
3556 edit_goto_cmd (edit);
3557 break;
3558 case CK_Paragraph_Format:
3559 format_paragraph (edit, 1);
3560 edit->force |= REDRAW_PAGE;
3561 break;
3562 case CK_Delete_Macro:
3563 edit_delete_macro_cmd (edit);
3564 break;
3565 case CK_Match_Bracket:
3566 edit_goto_matching_bracket (edit);
3567 break;
3568 case CK_User_Menu:
3569 user_menu (edit);
3570 break;
3571 case CK_Sort:
3572 edit_sort_cmd (edit);
3573 break;
3574 case CK_ExtCmd:
3575 edit_ext_cmd (edit);
3576 break;
3577 case CK_Mail:
3578 edit_mail_dialog (edit);
3579 break;
3580 case CK_Shell:
3581 view_other_cmd ();
3582 break;
3583 case CK_SelectCodepage:
3584 edit_select_codepage_cmd (edit);
3585 break;
3586 case CK_Insert_Literal:
3587 edit_insert_literal_cmd (edit);
3588 break;
3589 case CK_Execute_Macro:
3590 edit_execute_macro_cmd (edit);
3591 break;
3592 case CK_Begin_End_Macro:
3593 edit_begin_end_macro_cmd (edit);
3594 break;
3595 case CK_Ext_Mode:
3596 edit->extmod = 1;
3597 break;
3598 default:
3599 break;
3602 /* CK_Pipe_Block */
3603 if ((command / 1000) == 1) /* a shell command */
3604 edit_block_process_cmd (edit, shell_cmd[command - 1000], 1);
3605 if (command > CK_Macro (0) && command <= CK_Last_Macro)
3606 { /* a macro command */
3607 struct macro m[MAX_MACRO_LENGTH];
3608 int nm;
3609 if (edit_load_macro_cmd (edit, m, &nm, command - 2000))
3610 edit_execute_macro (edit, m, nm);
3613 /* keys which must set the col position, and the search vars */
3614 switch (command)
3616 case CK_Find:
3617 case CK_Find_Again:
3618 case CK_Replace:
3619 case CK_Replace_Again:
3620 case CK_Complete_Word:
3621 edit->prev_col = edit_get_col (edit);
3622 break;
3623 case CK_Up:
3624 case CK_Up_Highlight:
3625 case CK_Up_Alt_Highlight:
3626 case CK_Down:
3627 case CK_Down_Highlight:
3628 case CK_Down_Alt_Highlight:
3629 case CK_Page_Up:
3630 case CK_Page_Up_Highlight:
3631 case CK_Page_Up_Alt_Highlight:
3632 case CK_Page_Down:
3633 case CK_Page_Down_Highlight:
3634 case CK_Page_Down_Alt_Highlight:
3635 case CK_Beginning_Of_Text:
3636 case CK_Beginning_Of_Text_Highlight:
3637 case CK_End_Of_Text:
3638 case CK_End_Of_Text_Highlight:
3639 case CK_Paragraph_Up:
3640 case CK_Paragraph_Up_Highlight:
3641 case CK_Paragraph_Up_Alt_Highlight:
3642 case CK_Paragraph_Down:
3643 case CK_Paragraph_Down_Highlight:
3644 case CK_Paragraph_Down_Alt_Highlight:
3645 case CK_Scroll_Up:
3646 case CK_Scroll_Up_Highlight:
3647 case CK_Scroll_Up_Alt_Highlight:
3648 case CK_Scroll_Down:
3649 case CK_Scroll_Down_Highlight:
3650 case CK_Scroll_Down_Alt_Highlight:
3651 edit->search_start = edit->curs1;
3652 edit->found_len = 0;
3653 break;
3654 default:
3655 edit->found_len = 0;
3656 edit->prev_col = edit_get_col (edit);
3657 edit->search_start = edit->curs1;
3659 edit_find_bracket (edit);
3661 if (option_auto_para_formatting)
3663 switch (command)
3665 case CK_BackSpace:
3666 case CK_Delete:
3667 case CK_Delete_Word_Left:
3668 case CK_Delete_Word_Right:
3669 case CK_Delete_To_Line_End:
3670 case CK_Delete_To_Line_Begin:
3671 format_paragraph (edit, 0);
3672 edit->force |= REDRAW_PAGE;
3678 static void
3679 edit_execute_macro (WEdit * edit, struct macro macro[], int n)
3681 int i = 0;
3683 if (edit->macro_depth++ > 256)
3685 edit_error_dialog (_("Error"), _("Macro recursion is too deep"));
3686 edit->macro_depth--;
3687 return;
3689 edit->force |= REDRAW_PAGE;
3690 for (; i < n; i++)
3692 edit_execute_cmd (edit, macro[i].command, macro[i].ch);
3694 edit_update_screen (edit);
3695 edit->macro_depth--;
3698 /* User edit menu, like user menu (F2) but only in editor. */
3699 static void
3700 user_menu (WEdit * edit)
3702 char *block_file;
3703 int nomark;
3704 long start_mark, end_mark;
3705 struct stat status;
3707 block_file = concat_dir_and_file (home_dir, EDIT_BLOCK_FILE);
3709 nomark = eval_marks (edit, &start_mark, &end_mark);
3710 if (nomark == 0)
3711 edit_save_block (edit, block_file, start_mark, end_mark);
3713 /* run shell scripts from menu */
3714 user_menu_cmd (edit);
3716 if ((mc_stat (block_file, &status) == 0) && (status.st_size != 0))
3718 int rc = 0;
3719 FILE *fd;
3721 if (nomark == 0)
3723 /* i.e. we have marked block */
3724 rc = edit_block_delete_cmd (edit);
3727 if (rc == 0)
3728 edit_insert_file (edit, block_file);
3730 /* truncate block file */
3731 fd = fopen (block_file, "w");
3732 if (fd != NULL)
3733 fclose (fd);
3735 edit_refresh_cmd (edit);
3736 edit->force |= REDRAW_COMPLETELY;
3738 g_free (block_file);
3741 void
3742 edit_stack_init (void)
3744 for (edit_stack_iterator = 0; edit_stack_iterator < MAX_HISTORY_MOVETO; edit_stack_iterator++)
3746 edit_history_moveto[edit_stack_iterator].filename = NULL;
3747 edit_history_moveto[edit_stack_iterator].line = -1;
3750 edit_stack_iterator = 0;
3753 void
3754 edit_stack_free (void)
3756 for (edit_stack_iterator = 0; edit_stack_iterator < MAX_HISTORY_MOVETO; edit_stack_iterator++)
3757 g_free (edit_history_moveto[edit_stack_iterator].filename);
3760 /* move i lines */
3761 void
3762 edit_move_up (WEdit * edit, unsigned long i, int do_scroll)
3764 edit_move_updown (edit, i, do_scroll, TRUE);
3767 /* move i lines */
3768 void
3769 edit_move_down (WEdit * edit, unsigned long i, int do_scroll)
3771 edit_move_updown (edit, i, do_scroll, FALSE);