Ticket #3836: maint - set default `--with-homedir` value to `.mc` instead of `yes`
[midnight-commander.git] / src / editor / edit.c
blobeaab3c4d95a451897d1892f357cac45be8182f22
1 /*
2 Editor low level data handling and cursor fundamentals.
4 Copyright (C) 1996-2017
5 Free Software Foundation, Inc.
7 Written by:
8 Paul Sheer 1996, 1997
9 Ilia Maslakov <il.smind@gmail.com> 2009, 2010, 2011
10 Andrew Borodin <aborodin@vmail.ru> 2012, 2013
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 /** \file
29 * \brief Source: editor low level data handling and cursor fundamentals
30 * \author Paul Sheer
31 * \date 1996, 1997
34 #include <config.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <sys/stat.h>
43 #include <stdint.h> /* UINTMAX_MAX */
44 #include <stdlib.h>
46 #include "lib/global.h"
48 #include "lib/tty/color.h"
49 #include "lib/tty/tty.h" /* attrset() */
50 #include "lib/tty/key.h" /* is_idle() */
51 #include "lib/skin.h" /* EDITOR_NORMAL_COLOR */
52 #include "lib/fileloc.h" /* EDIT_BLOCK_FILE */
53 #include "lib/vfs/vfs.h"
54 #include "lib/strutil.h" /* utf string functions */
55 #include "lib/util.h" /* load_file_position(), save_file_position() */
56 #include "lib/timefmt.h" /* time formatting */
57 #include "lib/lock.h"
58 #include "lib/widget.h"
60 #ifdef HAVE_CHARSET
61 #include "lib/charsets.h" /* get_codepage_id */
62 #endif
64 #include "src/filemanager/usermenu.h" /* user_menu_cmd() */
66 #include "src/setup.h" /* option_tab_spacing */
67 #include "src/learn.h" /* learn_keys */
68 #include "src/keybind-defaults.h"
70 #include "edit-impl.h"
71 #include "editwidget.h"
72 #ifdef HAVE_ASPELL
73 #include "spell.h"
74 #endif
76 /*** global variables ****************************************************************************/
78 int option_word_wrap_line_length = DEFAULT_WRAP_LINE_LENGTH;
79 gboolean option_typewriter_wrap = FALSE;
80 gboolean option_auto_para_formatting = FALSE;
81 gboolean option_fill_tabs_with_spaces = FALSE;
82 gboolean option_return_does_auto_indent = TRUE;
83 gboolean option_backspace_through_tabs = FALSE;
84 gboolean option_fake_half_tabs = TRUE;
85 int option_save_mode = EDIT_QUICK_SAVE;
86 gboolean option_save_position = TRUE;
87 int option_max_undo = 32768;
88 gboolean option_persistent_selections = TRUE;
89 gboolean option_cursor_beyond_eol = FALSE;
90 gboolean option_line_state = FALSE;
91 int option_line_state_width = 0;
92 gboolean option_cursor_after_inserted_block = FALSE;
93 gboolean option_state_full_filename = FALSE;
95 gboolean enable_show_tabs_tws = TRUE;
96 gboolean option_check_nl_at_eof = FALSE;
97 gboolean option_group_undo = FALSE;
98 gboolean show_right_margin = FALSE;
100 char *option_backup_ext = NULL;
101 char *option_filesize_threshold = NULL;
103 unsigned int edit_stack_iterator = 0;
104 edit_stack_type edit_history_moveto[MAX_HISTORY_MOVETO];
105 /* magic sequense for say than block is vertical */
106 const char VERTICAL_MAGIC[] = { '\1', '\1', '\1', '\1', '\n' };
108 /*** file scope macro definitions ****************************************************************/
110 #define TEMP_BUF_LEN 1024
112 #define space_width 1
114 /*** file scope type declarations ****************************************************************/
116 /*** file scope variables ************************************************************************/
118 /* detecting an error on save is easy: just check if every byte has been written. */
119 /* detecting an error on read, is not so easy 'cos there is not way to tell
120 whether you read everything or not. */
121 /* FIXME: add proper 'triple_pipe_open' to read, write and check errors. */
122 static const struct edit_filters
124 const char *read, *write, *extension;
125 } all_filters[] =
127 /* *INDENT-OFF* */
128 { "xz -cd %s 2>&1", "xz > %s", ".xz"},
129 { "lz4 -cd %s 2>&1", "lz4 > %s", ".lz4" },
130 { "lzip -cd %s 2>&1", "lzip > %s", ".lz"},
131 { "lzma -cd %s 2>&1", "lzma > %s", ".lzma" },
132 { "bzip2 -cd %s 2>&1", "bzip2 > %s", ".bz2" },
133 { "gzip -cd %s 2>&1", "gzip > %s", ".gz" },
134 { "gzip -cd %s 2>&1", "gzip > %s", ".Z" }
135 /* *INDENT-ON* */
138 static const off_t option_filesize_default_threshold = 64 * 1024 * 1024; /* 64 MB */
140 /* --------------------------------------------------------------------------------------------- */
141 /*** file scope functions ************************************************************************/
142 /* --------------------------------------------------------------------------------------------- */
144 static int
145 edit_load_status_update_cb (status_msg_t * sm)
147 simple_status_msg_t *ssm = SIMPLE_STATUS_MSG (sm);
148 edit_buffer_read_file_status_msg_t *rsm = (edit_buffer_read_file_status_msg_t *) sm;
149 Widget *wd = WIDGET (sm->dlg);
151 if (verbose)
152 label_set_textv (ssm->label, _("Loading: %3d%%"),
153 edit_buffer_calc_percent (rsm->buf, rsm->loaded));
154 else
155 label_set_text (ssm->label, _("Loading..."));
157 if (rsm->first)
159 int wd_width;
160 Widget *lw = WIDGET (ssm->label);
162 wd_width = MAX (wd->cols, lw->cols + 6);
163 widget_set_size (wd, wd->y, wd->x, wd->lines, wd_width);
164 widget_set_size (lw, lw->y, wd->x + (wd->cols - lw->cols) / 2, lw->lines, lw->cols);
165 rsm->first = FALSE;
168 return status_msg_common_update (sm);
171 /* --------------------------------------------------------------------------------------------- */
173 * Load file OR text into buffers. Set cursor to the beginning of file.
175 * @return FALSE on error.
178 static gboolean
179 edit_load_file_fast (edit_buffer_t * buf, const vfs_path_t * filename_vpath)
181 int file;
182 gboolean ret;
183 edit_buffer_read_file_status_msg_t rsm;
184 gboolean aborted;
186 file = mc_open (filename_vpath, O_RDONLY | O_BINARY);
187 if (file < 0)
189 gchar *errmsg;
191 errmsg =
192 g_strdup_printf (_("Cannot open %s for reading"), vfs_path_as_str (filename_vpath));
193 edit_error_dialog (_("Error"), errmsg);
194 g_free (errmsg);
195 return FALSE;
198 rsm.first = TRUE;
199 rsm.buf = buf;
200 rsm.loaded = 0;
202 status_msg_init (STATUS_MSG (&rsm), _("Load file"), 1.0, simple_status_msg_init_cb,
203 edit_load_status_update_cb, NULL);
205 ret = (edit_buffer_read_file (buf, file, buf->size, &rsm, &aborted) == buf->size);
207 status_msg_deinit (STATUS_MSG (&rsm));
209 if (!ret && !aborted)
211 gchar *errmsg;
213 errmsg = g_strdup_printf (_("Error reading %s"), vfs_path_as_str (filename_vpath));
214 edit_error_dialog (_("Error"), errmsg);
215 g_free (errmsg);
218 mc_close (file);
219 return ret;
222 /* --------------------------------------------------------------------------------------------- */
223 /** Return index of the filter or -1 is there is no appropriate filter */
225 static int
226 edit_find_filter (const vfs_path_t * filename_vpath)
228 size_t i, l;
230 if (filename_vpath == NULL)
231 return -1;
233 l = strlen (vfs_path_as_str (filename_vpath));
234 for (i = 0; i < G_N_ELEMENTS (all_filters); i++)
236 size_t e;
238 e = strlen (all_filters[i].extension);
239 if (l > e)
240 if (!strcmp (all_filters[i].extension, vfs_path_as_str (filename_vpath) + l - e))
241 return i;
243 return -1;
246 /* --------------------------------------------------------------------------------------------- */
248 static char *
249 edit_get_filter (const vfs_path_t * filename_vpath)
251 int i;
252 char *p, *quoted_name;
254 i = edit_find_filter (filename_vpath);
255 if (i < 0)
256 return NULL;
258 quoted_name = name_quote (vfs_path_as_str (filename_vpath), FALSE);
259 p = g_strdup_printf (all_filters[i].read, quoted_name);
260 g_free (quoted_name);
261 return p;
264 /* --------------------------------------------------------------------------------------------- */
266 static off_t
267 edit_insert_stream (WEdit * edit, FILE * f)
269 int c;
270 off_t i = 0;
272 while ((c = fgetc (f)) >= 0)
274 edit_insert (edit, c);
275 i++;
277 return i;
280 /* --------------------------------------------------------------------------------------------- */
282 * Open file and create it if necessary.
284 * @param edit editor object
285 * @param filename_vpath file name
286 * @param st buffer for store stat info
287 * @return TRUE for success, FALSE for error.
290 static gboolean
291 check_file_access (WEdit * edit, const vfs_path_t * filename_vpath, struct stat *st)
293 static uintmax_t threshold = UINTMAX_MAX;
294 int file;
295 gchar *errmsg = NULL;
296 gboolean ret = TRUE;
298 /* Try opening an existing file */
299 file = mc_open (filename_vpath, O_NONBLOCK | O_RDONLY | O_BINARY, 0666);
300 if (file < 0)
303 * Try creating the file. O_EXCL prevents following broken links
304 * and opening existing files.
306 file = mc_open (filename_vpath, O_NONBLOCK | O_RDONLY | O_BINARY | O_CREAT | O_EXCL, 0666);
307 if (file < 0)
309 errmsg =
310 g_strdup_printf (_("Cannot open %s for reading"), vfs_path_as_str (filename_vpath));
311 goto cleanup;
314 /* New file, delete it if it's not modified or saved */
315 edit->delete_file = 1;
318 /* Check what we have opened */
319 if (mc_fstat (file, st) < 0)
321 errmsg =
322 g_strdup_printf (_("Cannot get size/permissions for %s"),
323 vfs_path_as_str (filename_vpath));
324 goto cleanup;
327 /* We want to open regular files only */
328 if (!S_ISREG (st->st_mode))
330 errmsg =
331 g_strdup_printf (_("\"%s\" is not a regular file"), vfs_path_as_str (filename_vpath));
332 goto cleanup;
335 /* get file size threshold for alarm */
336 if (threshold == UINTMAX_MAX)
338 gboolean err = FALSE;
340 threshold = parse_integer (option_filesize_threshold, &err);
341 if (err)
342 threshold = option_filesize_default_threshold;
346 * Don't delete non-empty files.
347 * O_EXCL should prevent it, but let's be on the safe side.
349 if (st->st_size > 0)
350 edit->delete_file = 0;
352 if ((uintmax_t) st->st_size > threshold)
354 int act;
356 errmsg = g_strdup_printf (_("File \"%s\" is too large.\nOpen it anyway?"),
357 vfs_path_as_str (filename_vpath));
358 act = edit_query_dialog2 (_("Warning"), errmsg, _("&Yes"), _("&No"));
359 MC_PTR_FREE (errmsg);
361 if (act != 0)
362 ret = FALSE;
365 cleanup:
366 (void) mc_close (file);
368 if (errmsg != NULL)
370 edit_error_dialog (_("Error"), errmsg);
371 g_free (errmsg);
372 ret = FALSE;
375 return ret;
378 /* --------------------------------------------------------------------------------------------- */
381 * Open the file and load it into the buffers, either directly or using
382 * a filter. Return TRUE on success, FALSE on error.
384 * Fast loading (edit_load_file_fast) is used when the file size is
385 * known. In this case the data is read into the buffers by blocks.
386 * If the file size is not known, the data is loaded byte by byte in
387 * edit_insert_file.
389 * @param edit editor object
390 * @return TRUE if file was successfully opened and loaded to buffers, FALSE otherwise
392 static gboolean
393 edit_load_file (WEdit * edit)
395 gboolean fast_load = TRUE;
397 /* Cannot do fast load if a filter is used */
398 if (edit_find_filter (edit->filename_vpath) >= 0)
399 fast_load = FALSE;
402 * FIXME: line end translation should disable fast loading as well
403 * Consider doing fseek() to the end and ftell() for the real size.
405 if (edit->filename_vpath != NULL)
408 * VFS may report file size incorrectly, and slow load is not a big
409 * deal considering overhead in VFS.
411 if (!vfs_file_is_local (edit->filename_vpath))
412 fast_load = FALSE;
414 /* If we are dealing with a real file, check that it exists */
415 if (!check_file_access (edit, edit->filename_vpath, &edit->stat1))
417 edit_clean (edit);
418 return FALSE;
421 else
423 /* nothing to load */
424 fast_load = FALSE;
427 if (fast_load)
429 edit_buffer_init (&edit->buffer, edit->stat1.st_size);
431 if (!edit_load_file_fast (&edit->buffer, edit->filename_vpath))
433 edit_clean (edit);
434 return FALSE;
437 else
439 edit_buffer_init (&edit->buffer, 0);
441 if (edit->filename_vpath != NULL
442 && *(vfs_path_get_by_index (edit->filename_vpath, 0)->path) != '\0')
444 edit->undo_stack_disable = 1;
445 if (edit_insert_file (edit, edit->filename_vpath) < 0)
447 edit_clean (edit);
448 return FALSE;
450 edit->undo_stack_disable = 0;
453 edit->lb = LB_ASIS;
454 return TRUE;
457 /* --------------------------------------------------------------------------------------------- */
459 * Restore saved cursor position and/or bookmarks in the file
461 * @param edit editor object
462 * @param load_position If TRUE, load bookmarks and cursor position and aply them.
463 * If FALSE, load bookmarks only.
466 static void
467 edit_load_position (WEdit * edit, gboolean load_position)
469 long line, column;
470 off_t offset;
472 if (edit->filename_vpath == NULL
473 || *(vfs_path_get_by_index (edit->filename_vpath, 0)->path) == '\0')
474 return;
476 load_file_position (edit->filename_vpath, &line, &column, &offset, &edit->serialized_bookmarks);
477 /* apply bookmarks in any case */
478 book_mark_restore (edit, BOOK_MARK_COLOR);
480 if (!load_position)
481 return;
483 if (line > 0)
485 edit_move_to_line (edit, line - 1);
486 edit->prev_col = column;
488 else if (offset > 0)
490 edit_cursor_move (edit, offset);
491 line = edit->buffer.curs_line;
492 edit->search_start = edit->buffer.curs1;
495 edit_move_to_prev_col (edit, edit_buffer_get_current_bol (&edit->buffer));
496 edit_move_display (edit, line - (WIDGET (edit)->lines / 2));
499 /* --------------------------------------------------------------------------------------------- */
500 /** Save cursor position in the file */
502 static void
503 edit_save_position (WEdit * edit)
505 if (edit->filename_vpath == NULL
506 || *(vfs_path_get_by_index (edit->filename_vpath, 0)->path) == '\0')
507 return;
509 book_mark_serialize (edit, BOOK_MARK_COLOR);
510 save_file_position (edit->filename_vpath, edit->buffer.curs_line + 1, edit->curs_col,
511 edit->buffer.curs1, edit->serialized_bookmarks);
512 edit->serialized_bookmarks = NULL;
515 /* --------------------------------------------------------------------------------------------- */
516 /** Clean the WEdit stricture except the widget part */
518 static void
519 edit_purge_widget (WEdit * edit)
521 size_t len = sizeof (WEdit) - sizeof (Widget);
522 char *start = (char *) edit + sizeof (Widget);
523 memset (start, 0, len);
526 /* --------------------------------------------------------------------------------------------- */
529 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
530 then the file should be as it was when he loaded up. Then set edit->modified to 0.
533 static long
534 edit_pop_undo_action (WEdit * edit)
536 long c;
537 unsigned long sp = edit->undo_stack_pointer;
539 if (sp == edit->undo_stack_bottom)
540 return STACK_BOTTOM;
542 sp = (sp - 1) & edit->undo_stack_size_mask;
543 c = edit->undo_stack[sp];
544 if (c >= 0)
546 /* edit->undo_stack[sp] = '@'; */
547 edit->undo_stack_pointer = (edit->undo_stack_pointer - 1) & edit->undo_stack_size_mask;
548 return c;
551 if (sp == edit->undo_stack_bottom)
552 return STACK_BOTTOM;
554 c = edit->undo_stack[(sp - 1) & edit->undo_stack_size_mask];
555 if (edit->undo_stack[sp] == -2)
557 /* edit->undo_stack[sp] = '@'; */
558 edit->undo_stack_pointer = sp;
560 else
561 edit->undo_stack[sp]++;
563 return c;
566 static long
567 edit_pop_redo_action (WEdit * edit)
569 long c;
570 unsigned long sp = edit->redo_stack_pointer;
572 if (sp == edit->redo_stack_bottom)
573 return STACK_BOTTOM;
575 sp = (sp - 1) & edit->redo_stack_size_mask;
576 c = edit->redo_stack[sp];
577 if (c >= 0)
579 edit->redo_stack_pointer = (edit->redo_stack_pointer - 1) & edit->redo_stack_size_mask;
580 return c;
583 if (sp == edit->redo_stack_bottom)
584 return STACK_BOTTOM;
586 c = edit->redo_stack[(sp - 1) & edit->redo_stack_size_mask];
587 if (edit->redo_stack[sp] == -2)
588 edit->redo_stack_pointer = sp;
589 else
590 edit->redo_stack[sp]++;
592 return c;
595 static long
596 get_prev_undo_action (WEdit * edit)
598 long c;
599 unsigned long sp = edit->undo_stack_pointer;
601 if (sp == edit->undo_stack_bottom)
602 return STACK_BOTTOM;
604 sp = (sp - 1) & edit->undo_stack_size_mask;
605 c = edit->undo_stack[sp];
606 if (c >= 0)
607 return c;
609 if (sp == edit->undo_stack_bottom)
610 return STACK_BOTTOM;
612 c = edit->undo_stack[(sp - 1) & edit->undo_stack_size_mask];
613 return c;
616 /* --------------------------------------------------------------------------------------------- */
617 /** is called whenever a modification is made by one of the four routines below */
619 static void
620 edit_modification (WEdit * edit)
622 edit->caches_valid = FALSE;
624 /* raise lock when file modified */
625 if (!edit->modified && !edit->delete_file)
626 edit->locked = lock_file (edit->filename_vpath);
627 edit->modified = 1;
630 /* --------------------------------------------------------------------------------------------- */
631 /* high level cursor movement commands */
632 /* --------------------------------------------------------------------------------------------- */
633 /** check whether cursor is in indent part of line
635 * @param edit editor object
637 * @return TRUE if cursor is in indent, FALSE otherwise
640 static gboolean
641 is_in_indent (const edit_buffer_t * buf)
643 off_t p;
645 for (p = edit_buffer_get_current_bol (buf); p < buf->curs1; p++)
646 if (strchr (" \t", edit_buffer_get_byte (buf, p)) == NULL)
647 return FALSE;
649 return TRUE;
652 /* --------------------------------------------------------------------------------------------- */
653 /** check whether line in editor is blank or not
655 * @param edit editor object
656 * @param offset position in file
658 * @return TRUE if line in blank, FALSE otherwise
661 static gboolean
662 is_blank (const edit_buffer_t * buf, off_t offset)
664 off_t s, f;
666 s = edit_buffer_get_bol (buf, offset);
667 f = edit_buffer_get_eol (buf, offset) - 1;
668 while (s <= f)
670 int c;
672 c = edit_buffer_get_byte (buf, s++);
673 if (!isspace (c))
674 return FALSE;
676 return TRUE;
679 /* --------------------------------------------------------------------------------------------- */
680 /** returns the offset of line i */
682 static off_t
683 edit_find_line (WEdit * edit, long line)
685 long i, j = 0;
686 long m = 2000000000; /* what is the magic number? */
688 if (!edit->caches_valid)
690 memset (edit->line_numbers, 0, sizeof (edit->line_numbers));
691 memset (edit->line_offsets, 0, sizeof (edit->line_offsets));
692 /* three offsets that we *know* are line 0 at 0 and these two: */
693 edit->line_numbers[1] = edit->buffer.curs_line;
694 edit->line_offsets[1] = edit_buffer_get_current_bol (&edit->buffer);
695 edit->line_numbers[2] = edit->buffer.lines;
696 edit->line_offsets[2] = edit_buffer_get_bol (&edit->buffer, edit->buffer.size);
697 edit->caches_valid = TRUE;
699 if (line >= edit->buffer.lines)
700 return edit->line_offsets[2];
701 if (line <= 0)
702 return 0;
703 /* find the closest known point */
704 for (i = 0; i < N_LINE_CACHES; i++)
706 long n;
708 n = labs (edit->line_numbers[i] - line);
709 if (n < m)
711 m = n;
712 j = i;
715 if (m == 0)
716 return edit->line_offsets[j]; /* know the offset exactly */
717 if (m == 1 && j >= 3)
718 i = j; /* one line different - caller might be looping, so stay in this cache */
719 else
720 i = 3 + (rand () % (N_LINE_CACHES - 3));
721 if (line > edit->line_numbers[j])
722 edit->line_offsets[i] =
723 edit_buffer_get_forward_offset (&edit->buffer, edit->line_offsets[j],
724 line - edit->line_numbers[j], 0);
725 else
726 edit->line_offsets[i] =
727 edit_buffer_get_backward_offset (&edit->buffer, edit->line_offsets[j],
728 edit->line_numbers[j] - line);
729 edit->line_numbers[i] = line;
730 return edit->line_offsets[i];
733 /* --------------------------------------------------------------------------------------------- */
734 /** moves up until a blank line is reached, or until just
735 before a non-blank line is reached */
737 static void
738 edit_move_up_paragraph (WEdit * edit, gboolean do_scroll)
740 long i = 0;
742 if (edit->buffer.curs_line > 1)
744 if (!edit_line_is_blank (edit, edit->buffer.curs_line))
746 for (i = edit->buffer.curs_line - 1; i != 0; i--)
747 if (edit_line_is_blank (edit, i))
748 break;
750 else if (edit_line_is_blank (edit, edit->buffer.curs_line - 1))
752 for (i = edit->buffer.curs_line - 1; i != 0; i--)
753 if (!edit_line_is_blank (edit, i))
755 i++;
756 break;
759 else
761 for (i = edit->buffer.curs_line - 1; i != 0; i--)
762 if (edit_line_is_blank (edit, i))
763 break;
767 edit_move_up (edit, edit->buffer.curs_line - i, do_scroll);
770 /* --------------------------------------------------------------------------------------------- */
771 /** moves down until a blank line is reached, or until just
772 before a non-blank line is reached */
774 static void
775 edit_move_down_paragraph (WEdit * edit, gboolean do_scroll)
777 long i;
779 if (edit->buffer.curs_line >= edit->buffer.lines - 1)
780 i = edit->buffer.lines;
781 else if (!edit_line_is_blank (edit, edit->buffer.curs_line))
783 for (i = edit->buffer.curs_line + 1; i != 0; i++)
784 if (edit_line_is_blank (edit, i) || i >= edit->buffer.lines)
785 break;
787 else if (edit_line_is_blank (edit, edit->buffer.curs_line + 1))
789 for (i = edit->buffer.curs_line + 1; i != 0; i++)
790 if (!edit_line_is_blank (edit, i) || i > edit->buffer.lines)
792 i--;
793 break;
796 else
798 for (i = edit->buffer.curs_line + 1; i != 0; i++)
799 if (edit_line_is_blank (edit, i) || i >= edit->buffer.lines)
800 break;
802 edit_move_down (edit, i - edit->buffer.curs_line, do_scroll);
805 /* --------------------------------------------------------------------------------------------- */
807 static void
808 edit_begin_page (WEdit * edit)
810 edit_update_curs_row (edit);
811 edit_move_up (edit, edit->curs_row, FALSE);
814 /* --------------------------------------------------------------------------------------------- */
816 static void
817 edit_end_page (WEdit * edit)
819 edit_update_curs_row (edit);
820 edit_move_down (edit, WIDGET (edit)->lines - edit->curs_row - 1, FALSE);
824 /* --------------------------------------------------------------------------------------------- */
825 /** goto beginning of text */
827 static void
828 edit_move_to_top (WEdit * edit)
830 if (edit->buffer.curs_line != 0)
832 edit_cursor_move (edit, -edit->buffer.curs1);
833 edit_move_to_prev_col (edit, 0);
834 edit->force |= REDRAW_PAGE;
835 edit->search_start = 0;
836 edit_update_curs_row (edit);
840 /* --------------------------------------------------------------------------------------------- */
841 /** goto end of text */
843 static void
844 edit_move_to_bottom (WEdit * edit)
846 if (edit->buffer.curs_line < edit->buffer.lines)
848 edit_move_down (edit, edit->buffer.lines - edit->curs_row, FALSE);
849 edit->start_display = edit->buffer.size;
850 edit->start_line = edit->buffer.lines;
851 edit_scroll_upward (edit, WIDGET (edit)->lines - 1);
852 edit->force |= REDRAW_PAGE;
856 /* --------------------------------------------------------------------------------------------- */
857 /** goto beginning of line */
859 static void
860 edit_cursor_to_bol (WEdit * edit)
862 edit_cursor_move (edit, edit_buffer_get_current_bol (&edit->buffer) - edit->buffer.curs1);
863 edit->search_start = edit->buffer.curs1;
864 edit->prev_col = edit_get_col (edit);
865 edit->over_col = 0;
868 /* --------------------------------------------------------------------------------------------- */
869 /** goto end of line */
871 static void
872 edit_cursor_to_eol (WEdit * edit)
874 edit_cursor_move (edit, edit_buffer_get_current_eol (&edit->buffer) - edit->buffer.curs1);
875 edit->search_start = edit->buffer.curs1;
876 edit->prev_col = edit_get_col (edit);
877 edit->over_col = 0;
880 /* --------------------------------------------------------------------------------------------- */
882 static unsigned long
883 my_type_of (int c)
885 unsigned long x, r = 0;
886 const char *p, *q;
887 const char option_chars_move_whole_word[] =
888 "!=&|<>^~ !:;, !'!`!.?!\"!( !) !{ !} !Aa0 !+-*/= |<> ![ !] !\\#! ";
890 if (c == 0)
891 return 0;
892 if (c == '!')
894 if (*option_chars_move_whole_word == '!')
895 return 2;
896 return 0x80000000UL;
898 if (g_ascii_isupper ((gchar) c))
899 c = 'A';
900 else if (g_ascii_islower ((gchar) c))
901 c = 'a';
902 else if (g_ascii_isalpha (c))
903 c = 'a';
904 else if (isdigit (c))
905 c = '0';
906 else if (isspace (c))
907 c = ' ';
908 q = strchr (option_chars_move_whole_word, c);
909 if (!q)
910 return 0xFFFFFFFFUL;
913 for (x = 1, p = option_chars_move_whole_word; p < q; p++)
914 if (*p == '!')
915 x <<= 1;
916 r |= x;
918 while ((q = strchr (q + 1, c)));
919 return r;
922 /* --------------------------------------------------------------------------------------------- */
924 static void
925 edit_left_word_move (WEdit * edit, int s)
927 while (TRUE)
929 int c1, c2;
931 if (edit->column_highlight
932 && edit->mark1 != edit->mark2
933 && edit->over_col == 0
934 && edit->buffer.curs1 == edit_buffer_get_current_bol (&edit->buffer))
935 break;
936 edit_cursor_move (edit, -1);
937 if (edit->buffer.curs1 == 0)
938 break;
939 c1 = edit_buffer_get_previous_byte (&edit->buffer);
940 c2 = edit_buffer_get_current_byte (&edit->buffer);
941 if (c1 == '\n' || c2 == '\n')
942 break;
943 if ((my_type_of (c1) & my_type_of (c2)) == 0)
944 break;
945 if (isspace (c1) && !isspace (c2))
946 break;
947 if (s != 0 && !isspace (c1) && isspace (c2))
948 break;
952 /* --------------------------------------------------------------------------------------------- */
954 static void
955 edit_left_word_move_cmd (WEdit * edit)
957 edit_left_word_move (edit, 0);
958 edit->force |= REDRAW_PAGE;
961 /* --------------------------------------------------------------------------------------------- */
963 static void
964 edit_right_word_move (WEdit * edit, int s)
966 while (TRUE)
968 int c1, c2;
970 if (edit->column_highlight
971 && edit->mark1 != edit->mark2
972 && edit->over_col == 0
973 && edit->buffer.curs1 == edit_buffer_get_current_eol (&edit->buffer))
974 break;
975 edit_cursor_move (edit, 1);
976 if (edit->buffer.curs1 >= edit->buffer.size)
977 break;
978 c1 = edit_buffer_get_previous_byte (&edit->buffer);
979 c2 = edit_buffer_get_current_byte (&edit->buffer);
980 if (c1 == '\n' || c2 == '\n')
981 break;
982 if ((my_type_of (c1) & my_type_of (c2)) == 0)
983 break;
984 if (isspace (c1) && !isspace (c2))
985 break;
986 if (s != 0 && !isspace (c1) && isspace (c2))
987 break;
991 /* --------------------------------------------------------------------------------------------- */
993 static void
994 edit_right_word_move_cmd (WEdit * edit)
996 edit_right_word_move (edit, 0);
997 edit->force |= REDRAW_PAGE;
1000 /* --------------------------------------------------------------------------------------------- */
1002 static void
1003 edit_right_char_move_cmd (WEdit * edit)
1005 int char_length = 1;
1006 int c;
1008 #ifdef HAVE_CHARSET
1009 if (edit->utf8)
1011 c = edit_buffer_get_utf (&edit->buffer, edit->buffer.curs1, &char_length);
1012 if (char_length < 1)
1013 char_length = 1;
1015 else
1016 #endif
1017 c = edit_buffer_get_current_byte (&edit->buffer);
1019 if (option_cursor_beyond_eol && c == '\n')
1020 edit->over_col++;
1021 else
1022 edit_cursor_move (edit, char_length);
1025 /* --------------------------------------------------------------------------------------------- */
1027 static void
1028 edit_left_char_move_cmd (WEdit * edit)
1030 int char_length = 1;
1032 if (edit->column_highlight
1033 && option_cursor_beyond_eol
1034 && edit->mark1 != edit->mark2
1035 && edit->over_col == 0 && edit->buffer.curs1 == edit_buffer_get_current_bol (&edit->buffer))
1036 return;
1037 #ifdef HAVE_CHARSET
1038 if (edit->utf8)
1040 edit_buffer_get_prev_utf (&edit->buffer, edit->buffer.curs1, &char_length);
1041 if (char_length < 1)
1042 char_length = 1;
1044 #endif
1046 if (option_cursor_beyond_eol && edit->over_col > 0)
1047 edit->over_col--;
1048 else
1049 edit_cursor_move (edit, -char_length);
1052 /* --------------------------------------------------------------------------------------------- */
1053 /** Up or down cursor moving.
1054 direction = TRUE - move up
1055 = FALSE - move down
1058 static void
1059 edit_move_updown (WEdit * edit, long lines, gboolean do_scroll, gboolean direction)
1061 long p;
1062 long l = direction ? edit->buffer.curs_line : edit->buffer.lines - edit->buffer.curs_line;
1064 if (lines > l)
1065 lines = l;
1067 if (lines == 0)
1068 return;
1070 if (lines > 1)
1071 edit->force |= REDRAW_PAGE;
1072 if (do_scroll)
1074 if (direction)
1075 edit_scroll_upward (edit, lines);
1076 else
1077 edit_scroll_downward (edit, lines);
1079 p = edit_buffer_get_current_bol (&edit->buffer);
1080 p = direction ? edit_buffer_get_backward_offset (&edit->buffer, p, lines) :
1081 edit_buffer_get_forward_offset (&edit->buffer, p, lines, 0);
1082 edit_cursor_move (edit, p - edit->buffer.curs1);
1083 edit_move_to_prev_col (edit, p);
1085 #ifdef HAVE_CHARSET
1086 /* search start of current multibyte char (like CJK) */
1087 if (edit->buffer.curs1 > 0 && edit->buffer.curs1 + 1 < edit->buffer.size
1088 && edit_buffer_get_current_byte (&edit->buffer) >= 256)
1090 edit_right_char_move_cmd (edit);
1091 edit_left_char_move_cmd (edit);
1093 #endif
1095 edit->search_start = edit->buffer.curs1;
1096 edit->found_len = 0;
1099 /* --------------------------------------------------------------------------------------------- */
1101 static void
1102 edit_right_delete_word (WEdit * edit)
1104 while (edit->buffer.curs1 < edit->buffer.size)
1106 int c1, c2;
1108 c1 = edit_delete (edit, TRUE);
1109 c2 = edit_buffer_get_current_byte (&edit->buffer);
1110 if (c1 == '\n' || c2 == '\n')
1111 break;
1112 if ((isspace (c1) == 0) != (isspace (c2) == 0))
1113 break;
1114 if ((my_type_of (c1) & my_type_of (c2)) == 0)
1115 break;
1119 /* --------------------------------------------------------------------------------------------- */
1121 static void
1122 edit_left_delete_word (WEdit * edit)
1124 while (edit->buffer.curs1 > 0)
1126 int c1, c2;
1128 c1 = edit_backspace (edit, TRUE);
1129 c2 = edit_buffer_get_previous_byte (&edit->buffer);
1130 if (c1 == '\n' || c2 == '\n')
1131 break;
1132 if ((isspace (c1) == 0) != (isspace (c2) == 0))
1133 break;
1134 if ((my_type_of (c1) & my_type_of (c2)) == 0)
1135 break;
1139 /* --------------------------------------------------------------------------------------------- */
1141 the start column position is not recorded, and hence does not
1142 undo as it happed. But who would notice.
1145 static void
1146 edit_do_undo (WEdit * edit)
1148 long ac;
1149 long count = 0;
1151 edit->undo_stack_disable = 1; /* don't record undo's onto undo stack! */
1152 edit->over_col = 0;
1153 while ((ac = edit_pop_undo_action (edit)) < KEY_PRESS)
1155 switch ((int) ac)
1157 case STACK_BOTTOM:
1158 goto done_undo;
1159 case CURS_RIGHT:
1160 edit_cursor_move (edit, 1);
1161 break;
1162 case CURS_LEFT:
1163 edit_cursor_move (edit, -1);
1164 break;
1165 case BACKSPACE:
1166 case BACKSPACE_BR:
1167 edit_backspace (edit, TRUE);
1168 break;
1169 case DELCHAR:
1170 case DELCHAR_BR:
1171 edit_delete (edit, TRUE);
1172 break;
1173 case COLUMN_ON:
1174 edit->column_highlight = 1;
1175 break;
1176 case COLUMN_OFF:
1177 edit->column_highlight = 0;
1178 break;
1179 default:
1180 break;
1182 if (ac >= 256 && ac < 512)
1183 edit_insert_ahead (edit, ac - 256);
1184 if (ac >= 0 && ac < 256)
1185 edit_insert (edit, ac);
1187 if (ac >= MARK_1 - 2 && ac < MARK_2 - 2)
1189 edit->mark1 = ac - MARK_1;
1190 edit->column1 =
1191 (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, edit->mark1),
1192 0, edit->mark1);
1194 if (ac >= MARK_2 - 2 && ac < MARK_CURS - 2)
1196 edit->mark2 = ac - MARK_2;
1197 edit->column2 =
1198 (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, edit->mark2),
1199 0, edit->mark2);
1201 else if (ac >= MARK_CURS - 2 && ac < KEY_PRESS)
1203 edit->end_mark_curs = ac - MARK_CURS;
1205 if (count++)
1206 edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
1209 if (edit->start_display > ac - KEY_PRESS)
1211 edit->start_line -=
1212 edit_buffer_count_lines (&edit->buffer, ac - KEY_PRESS, edit->start_display);
1213 edit->force |= REDRAW_PAGE;
1215 else if (edit->start_display < ac - KEY_PRESS)
1217 edit->start_line +=
1218 edit_buffer_count_lines (&edit->buffer, edit->start_display, ac - KEY_PRESS);
1219 edit->force |= REDRAW_PAGE;
1221 edit->start_display = ac - KEY_PRESS; /* see push and pop above */
1222 edit_update_curs_row (edit);
1224 done_undo:
1225 edit->undo_stack_disable = 0;
1228 /* --------------------------------------------------------------------------------------------- */
1230 static void
1231 edit_do_redo (WEdit * edit)
1233 long ac;
1234 long count = 0;
1236 if (edit->redo_stack_reset)
1237 return;
1239 edit->over_col = 0;
1240 while ((ac = edit_pop_redo_action (edit)) < KEY_PRESS)
1242 switch ((int) ac)
1244 case STACK_BOTTOM:
1245 goto done_redo;
1246 case CURS_RIGHT:
1247 edit_cursor_move (edit, 1);
1248 break;
1249 case CURS_LEFT:
1250 edit_cursor_move (edit, -1);
1251 break;
1252 case BACKSPACE:
1253 edit_backspace (edit, TRUE);
1254 break;
1255 case DELCHAR:
1256 edit_delete (edit, TRUE);
1257 break;
1258 case COLUMN_ON:
1259 edit->column_highlight = 1;
1260 break;
1261 case COLUMN_OFF:
1262 edit->column_highlight = 0;
1263 break;
1264 default:
1265 break;
1267 if (ac >= 256 && ac < 512)
1268 edit_insert_ahead (edit, ac - 256);
1269 if (ac >= 0 && ac < 256)
1270 edit_insert (edit, ac);
1272 if (ac >= MARK_1 - 2 && ac < MARK_2 - 2)
1274 edit->mark1 = ac - MARK_1;
1275 edit->column1 =
1276 (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, edit->mark1),
1277 0, edit->mark1);
1279 else if (ac >= MARK_2 - 2 && ac < KEY_PRESS)
1281 edit->mark2 = ac - MARK_2;
1282 edit->column2 =
1283 (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, edit->mark2),
1284 0, edit->mark2);
1286 /* more than one pop usually means something big */
1287 if (count++)
1288 edit->force |= REDRAW_PAGE;
1291 if (edit->start_display > ac - KEY_PRESS)
1293 edit->start_line -=
1294 edit_buffer_count_lines (&edit->buffer, ac - KEY_PRESS, edit->start_display);
1295 edit->force |= REDRAW_PAGE;
1297 else if (edit->start_display < ac - KEY_PRESS)
1299 edit->start_line +=
1300 edit_buffer_count_lines (&edit->buffer, edit->start_display, ac - KEY_PRESS);
1301 edit->force |= REDRAW_PAGE;
1303 edit->start_display = ac - KEY_PRESS; /* see push and pop above */
1304 edit_update_curs_row (edit);
1306 done_redo:
1310 /* --------------------------------------------------------------------------------------------- */
1312 static void
1313 edit_group_undo (WEdit * edit)
1315 long ac = KEY_PRESS;
1316 long cur_ac = KEY_PRESS;
1317 while (ac != STACK_BOTTOM && ac == cur_ac)
1319 cur_ac = get_prev_undo_action (edit);
1320 edit_do_undo (edit);
1321 ac = get_prev_undo_action (edit);
1322 /* exit from cycle if option_group_undo is not set,
1323 * and make single UNDO operation
1325 if (!option_group_undo)
1326 ac = STACK_BOTTOM;
1330 /* --------------------------------------------------------------------------------------------- */
1332 static void
1333 edit_delete_to_line_end (WEdit * edit)
1335 while (edit_buffer_get_current_byte (&edit->buffer) != '\n' && edit->buffer.curs2 != 0)
1336 edit_delete (edit, TRUE);
1339 /* --------------------------------------------------------------------------------------------- */
1341 static void
1342 edit_delete_to_line_begin (WEdit * edit)
1344 while (edit_buffer_get_previous_byte (&edit->buffer) != '\n' && edit->buffer.curs1 != 0)
1345 edit_backspace (edit, TRUE);
1348 /* --------------------------------------------------------------------------------------------- */
1350 static gboolean
1351 is_aligned_on_a_tab (WEdit * edit)
1353 long curs_col;
1355 edit_update_curs_col (edit);
1356 curs_col = edit->curs_col % (TAB_SIZE * space_width);
1357 return (curs_col == 0 || curs_col == (HALF_TAB_SIZE * space_width));
1360 /* --------------------------------------------------------------------------------------------- */
1362 static gboolean
1363 right_of_four_spaces (WEdit * edit)
1365 int i, ch = 0;
1367 for (i = 1; i <= HALF_TAB_SIZE; i++)
1368 ch |= edit_buffer_get_byte (&edit->buffer, edit->buffer.curs1 - i);
1370 return (ch == ' ' && is_aligned_on_a_tab (edit));
1373 /* --------------------------------------------------------------------------------------------- */
1375 static gboolean
1376 left_of_four_spaces (WEdit * edit)
1378 int i, ch = 0;
1380 for (i = 0; i < HALF_TAB_SIZE; i++)
1381 ch |= edit_buffer_get_byte (&edit->buffer, edit->buffer.curs1 + i);
1383 return (ch == ' ' && is_aligned_on_a_tab (edit));
1386 /* --------------------------------------------------------------------------------------------- */
1388 static void
1389 edit_auto_indent (WEdit * edit)
1391 off_t p;
1393 p = edit->buffer.curs1;
1394 /* use the previous line as a template */
1395 p = edit_buffer_get_backward_offset (&edit->buffer, p, 1);
1396 /* copy the leading whitespace of the line */
1397 while (TRUE)
1398 { /* no range check - the line _is_ \n-terminated */
1399 char c;
1401 c = edit_buffer_get_byte (&edit->buffer, p++);
1402 if (!whitespace (c))
1403 break;
1404 edit_insert (edit, c);
1408 /* --------------------------------------------------------------------------------------------- */
1410 static inline void
1411 edit_double_newline (WEdit * edit)
1413 edit_insert (edit, '\n');
1414 if (edit_buffer_get_current_byte (&edit->buffer) == '\n'
1415 || edit_buffer_get_byte (&edit->buffer, edit->buffer.curs1 - 2) == '\n')
1416 return;
1417 edit->force |= REDRAW_PAGE;
1418 edit_insert (edit, '\n');
1421 /* --------------------------------------------------------------------------------------------- */
1423 static void
1424 insert_spaces_tab (WEdit * edit, gboolean half)
1426 long i;
1428 edit_update_curs_col (edit);
1429 i = option_tab_spacing * space_width;
1430 if (half)
1431 i /= 2;
1432 if (i != 0)
1434 i = ((edit->curs_col / i) + 1) * i - edit->curs_col;
1435 while (i > 0)
1437 edit_insert (edit, ' ');
1438 i -= space_width;
1443 /* --------------------------------------------------------------------------------------------- */
1445 static inline void
1446 edit_tab_cmd (WEdit * edit)
1448 if (option_fake_half_tabs && is_in_indent (&edit->buffer))
1450 /* insert a half tab (usually four spaces) unless there is a
1451 half tab already behind, then delete it and insert a
1452 full tab. */
1453 if (option_fill_tabs_with_spaces || !right_of_four_spaces (edit))
1454 insert_spaces_tab (edit, TRUE);
1455 else
1457 int i;
1459 for (i = 1; i <= HALF_TAB_SIZE; i++)
1460 edit_backspace (edit, TRUE);
1461 edit_insert (edit, '\t');
1464 else if (option_fill_tabs_with_spaces)
1465 insert_spaces_tab (edit, FALSE);
1466 else
1467 edit_insert (edit, '\t');
1470 /* --------------------------------------------------------------------------------------------- */
1472 static void
1473 check_and_wrap_line (WEdit * edit)
1475 off_t curs;
1477 if (!option_typewriter_wrap)
1478 return;
1479 edit_update_curs_col (edit);
1480 if (edit->curs_col < option_word_wrap_line_length)
1481 return;
1482 curs = edit->buffer.curs1;
1483 while (TRUE)
1485 int c;
1487 curs--;
1488 c = edit_buffer_get_byte (&edit->buffer, curs);
1489 if (c == '\n' || curs <= 0)
1491 edit_insert (edit, '\n');
1492 return;
1494 if (whitespace (c))
1496 off_t current = edit->buffer.curs1;
1497 edit_cursor_move (edit, curs - edit->buffer.curs1 + 1);
1498 edit_insert (edit, '\n');
1499 edit_cursor_move (edit, current - edit->buffer.curs1 + 1);
1500 return;
1505 /* --------------------------------------------------------------------------------------------- */
1506 /** this find the matching bracket in either direction, and sets edit->bracket
1508 * @param edit editor object
1509 * @param in_screen seach only on the current screen
1510 * @param furthest_bracket_search count of the bytes for search
1512 * @return position of the found bracket (-1 if no match)
1515 static off_t
1516 edit_get_bracket (WEdit * edit, gboolean in_screen, unsigned long furthest_bracket_search)
1518 const char *const b = "{}{[][()(", *p;
1519 int i = 1, inc = -1, c, d, n = 0;
1520 unsigned long j = 0;
1521 off_t q;
1523 edit_update_curs_row (edit);
1524 c = edit_buffer_get_current_byte (&edit->buffer);
1525 p = strchr (b, c);
1526 /* not on a bracket at all */
1527 if (p == NULL || *p == '\0')
1528 return -1;
1529 /* the matching bracket */
1530 d = p[1];
1531 /* going left or right? */
1532 if (strchr ("{[(", c) != NULL)
1533 inc = 1;
1534 /* no limit */
1535 if (furthest_bracket_search == 0)
1536 furthest_bracket_search--; /* ULONG_MAX */
1537 for (q = edit->buffer.curs1 + inc;; q += inc)
1539 int a;
1541 /* out of buffer? */
1542 if (q >= edit->buffer.size || q < 0)
1543 break;
1544 a = edit_buffer_get_byte (&edit->buffer, q);
1545 /* don't want to eat CPU */
1546 if (j++ > furthest_bracket_search)
1547 break;
1548 /* out of screen? */
1549 if (in_screen)
1551 if (q < edit->start_display)
1552 break;
1553 /* count lines if searching downward */
1554 if (inc > 0 && a == '\n')
1555 if (n++ >= WIDGET (edit)->lines - edit->curs_row) /* out of screen */
1556 break;
1558 /* count bracket depth */
1559 i += (a == c) - (a == d);
1560 /* return if bracket depth is zero */
1561 if (i == 0)
1562 return q;
1564 /* no match */
1565 return -1;
1568 /* --------------------------------------------------------------------------------------------- */
1570 static inline void
1571 edit_goto_matching_bracket (WEdit * edit)
1573 off_t q;
1575 q = edit_get_bracket (edit, 0, 0);
1576 if (q >= 0)
1578 edit->bracket = edit->buffer.curs1;
1579 edit->force |= REDRAW_PAGE;
1580 edit_cursor_move (edit, q - edit->buffer.curs1);
1584 /* --------------------------------------------------------------------------------------------- */
1586 static void
1587 edit_move_block_to_right (WEdit * edit)
1589 off_t start_mark, end_mark;
1590 long cur_bol, start_bol;
1592 if (!eval_marks (edit, &start_mark, &end_mark))
1593 return;
1595 start_bol = edit_buffer_get_bol (&edit->buffer, start_mark);
1596 cur_bol = edit_buffer_get_bol (&edit->buffer, end_mark - 1);
1600 edit_cursor_move (edit, cur_bol - edit->buffer.curs1);
1601 if (!edit_line_is_blank (edit, edit->buffer.curs_line))
1603 if (option_fill_tabs_with_spaces)
1604 insert_spaces_tab (edit, option_fake_half_tabs);
1605 else
1606 edit_insert (edit, '\t');
1607 edit_cursor_move (edit,
1608 edit_buffer_get_bol (&edit->buffer, cur_bol) - edit->buffer.curs1);
1611 if (cur_bol == 0)
1612 break;
1614 cur_bol = edit_buffer_get_bol (&edit->buffer, cur_bol - 1);
1616 while (cur_bol >= start_bol);
1618 edit->force |= REDRAW_PAGE;
1621 /* --------------------------------------------------------------------------------------------- */
1623 static void
1624 edit_move_block_to_left (WEdit * edit)
1626 off_t start_mark, end_mark;
1627 off_t cur_bol, start_bol;
1629 if (!eval_marks (edit, &start_mark, &end_mark))
1630 return;
1632 start_bol = edit_buffer_get_bol (&edit->buffer, start_mark);
1633 cur_bol = edit_buffer_get_bol (&edit->buffer, end_mark - 1);
1637 int del_tab_width;
1638 int next_char;
1640 edit_cursor_move (edit, cur_bol - edit->buffer.curs1);
1642 if (option_fake_half_tabs)
1643 del_tab_width = HALF_TAB_SIZE;
1644 else
1645 del_tab_width = option_tab_spacing;
1647 next_char = edit_buffer_get_current_byte (&edit->buffer);
1648 if (next_char == '\t')
1649 edit_delete (edit, TRUE);
1650 else if (next_char == ' ')
1652 int i;
1654 for (i = 0; i < del_tab_width; i++)
1656 if (next_char == ' ')
1657 edit_delete (edit, TRUE);
1658 next_char = edit_buffer_get_current_byte (&edit->buffer);
1662 if (cur_bol == 0)
1663 break;
1665 cur_bol = edit_buffer_get_bol (&edit->buffer, cur_bol - 1);
1667 while (cur_bol >= start_bol);
1669 edit->force |= REDRAW_PAGE;
1672 /* --------------------------------------------------------------------------------------------- */
1674 * prints at the cursor
1675 * @return number of chars printed
1678 static size_t
1679 edit_print_string (WEdit * e, const char *s)
1681 size_t i = 0;
1683 while (s[i] != '\0')
1684 edit_execute_cmd (e, CK_InsertChar, (unsigned char) s[i++]);
1685 e->force |= REDRAW_COMPLETELY;
1686 edit_update_screen (e);
1687 return i;
1690 /* --------------------------------------------------------------------------------------------- */
1692 static off_t
1693 edit_insert_column_from_file (WEdit * edit, int file, off_t * start_pos, off_t * end_pos,
1694 long *col1, long *col2)
1696 off_t cursor;
1697 long col;
1698 off_t blocklen = -1, width = 0;
1699 unsigned char *data;
1701 cursor = edit->buffer.curs1;
1702 col = edit_get_col (edit);
1703 data = g_malloc0 (TEMP_BUF_LEN);
1705 while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0)
1707 off_t i;
1708 char *pn;
1710 pn = strchr ((char *) data, '\n');
1711 width = pn == NULL ? blocklen : pn - (char *) data;
1713 for (i = 0; i < blocklen; i++)
1715 if (data[i] != '\n')
1716 edit_insert (edit, data[i]);
1717 else
1718 { /* fill in and move to next line */
1719 long l;
1720 off_t p;
1722 if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
1723 for (l = width - (edit_get_col (edit) - col); l > 0; l -= space_width)
1724 edit_insert (edit, ' ');
1726 for (p = edit->buffer.curs1;; p++)
1728 if (p == edit->buffer.size)
1730 edit_cursor_move (edit, edit->buffer.size - edit->buffer.curs1);
1731 edit_insert_ahead (edit, '\n');
1732 p++;
1733 break;
1735 if (edit_buffer_get_byte (&edit->buffer, p) == '\n')
1737 p++;
1738 break;
1742 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->buffer.curs1);
1744 for (l = col - edit_get_col (edit); l >= space_width; l -= space_width)
1745 edit_insert (edit, ' ');
1749 *col1 = col;
1750 *col2 = col + width;
1751 *start_pos = cursor;
1752 *end_pos = edit->buffer.curs1;
1753 edit_cursor_move (edit, cursor - edit->buffer.curs1);
1754 g_free (data);
1756 return blocklen;
1759 /* --------------------------------------------------------------------------------------------- */
1760 /*** public functions ****************************************************************************/
1761 /* --------------------------------------------------------------------------------------------- */
1763 /** User edit menu, like user menu (F2) but only in editor. */
1765 void
1766 user_menu (WEdit * edit, const char *menu_file, int selected_entry)
1768 char *block_file;
1769 gboolean nomark;
1770 off_t curs;
1771 off_t start_mark, end_mark;
1772 struct stat status;
1773 vfs_path_t *block_file_vpath;
1775 block_file = mc_config_get_full_path (EDIT_BLOCK_FILE);
1776 block_file_vpath = vfs_path_from_str (block_file);
1777 curs = edit->buffer.curs1;
1778 nomark = !eval_marks (edit, &start_mark, &end_mark);
1779 if (!nomark)
1780 edit_save_block (edit, block_file, start_mark, end_mark);
1782 /* run shell scripts from menu */
1783 if (user_menu_cmd (edit, menu_file, selected_entry)
1784 && (mc_stat (block_file_vpath, &status) == 0) && (status.st_size != 0))
1786 int rc = 0;
1787 FILE *fd;
1789 /* i.e. we have marked block */
1790 if (!nomark)
1791 rc = edit_block_delete_cmd (edit);
1793 if (rc == 0)
1795 off_t ins_len;
1797 ins_len = edit_insert_file (edit, block_file_vpath);
1798 if (!nomark && ins_len > 0)
1799 edit_set_markers (edit, start_mark, start_mark + ins_len, 0, 0);
1801 /* truncate block file */
1802 fd = fopen (block_file, "w");
1803 if (fd != NULL)
1804 fclose (fd);
1806 g_free (block_file);
1807 vfs_path_free (block_file_vpath);
1809 edit_cursor_move (edit, curs - edit->buffer.curs1);
1810 edit->force |= REDRAW_PAGE;
1811 widget_redraw (WIDGET (edit));
1814 /* --------------------------------------------------------------------------------------------- */
1816 char *
1817 edit_get_write_filter (const vfs_path_t * write_name_vpath, const vfs_path_t * filename_vpath)
1819 int i;
1820 char *p, *writename;
1821 const vfs_path_element_t *path_element;
1823 i = edit_find_filter (filename_vpath);
1824 if (i < 0)
1825 return NULL;
1827 path_element = vfs_path_get_by_index (write_name_vpath, -1);
1828 writename = name_quote (path_element->path, FALSE);
1829 p = g_strdup_printf (all_filters[i].write, writename);
1830 g_free (writename);
1831 return p;
1834 /* --------------------------------------------------------------------------------------------- */
1836 * @param edit editor object
1837 * @param f value of stream file
1838 * @return the length of the file
1841 off_t
1842 edit_write_stream (WEdit * edit, FILE * f)
1844 long i;
1846 if (edit->lb == LB_ASIS)
1848 for (i = 0; i < edit->buffer.size; i++)
1849 if (fputc (edit_buffer_get_byte (&edit->buffer, i), f) < 0)
1850 break;
1851 return i;
1854 /* change line breaks */
1855 for (i = 0; i < edit->buffer.size; i++)
1857 unsigned char c;
1859 c = edit_buffer_get_byte (&edit->buffer, i);
1860 if (!(c == '\n' || c == '\r'))
1862 /* not line break */
1863 if (fputc (c, f) < 0)
1864 return i;
1866 else
1867 { /* (c == '\n' || c == '\r') */
1868 unsigned char c1;
1870 c1 = edit_buffer_get_byte (&edit->buffer, i + 1); /* next char */
1872 switch (edit->lb)
1874 case LB_UNIX: /* replace "\r\n" or '\r' to '\n' */
1875 /* put one line break unconditionally */
1876 if (fputc ('\n', f) < 0)
1877 return i;
1879 i++; /* 2 chars are processed */
1881 if (c == '\r' && c1 == '\n')
1882 /* Windows line break; go to the next char */
1883 break;
1885 if (c == '\r' && c1 == '\r')
1887 /* two Macintosh line breaks; put second line break */
1888 if (fputc ('\n', f) < 0)
1889 return i;
1890 break;
1893 if (fputc (c1, f) < 0)
1894 return i;
1895 break;
1897 case LB_WIN: /* replace '\n' or '\r' to "\r\n" */
1898 /* put one line break unconditionally */
1899 if (fputc ('\r', f) < 0 || fputc ('\n', f) < 0)
1900 return i;
1902 if (c == '\r' && c1 == '\n')
1903 /* Windows line break; go to the next char */
1904 i++;
1905 break;
1907 case LB_MAC: /* replace "\r\n" or '\n' to '\r' */
1908 /* put one line break unconditionally */
1909 if (fputc ('\r', f) < 0)
1910 return i;
1912 i++; /* 2 chars are processed */
1914 if (c == '\r' && c1 == '\n')
1915 /* Windows line break; go to the next char */
1916 break;
1918 if (c == '\n' && c1 == '\n')
1920 /* two Windows line breaks; put second line break */
1921 if (fputc ('\r', f) < 0)
1922 return i;
1923 break;
1926 if (fputc (c1, f) < 0)
1927 return i;
1928 break;
1929 case LB_ASIS: /* default without changes */
1930 default:
1931 break;
1936 return edit->buffer.size;
1939 /* --------------------------------------------------------------------------------------------- */
1941 gboolean
1942 is_break_char (char c)
1944 return (isspace (c) || strchr ("{}[]()<>=|/\\!?~-+`'\",.;:#$%^&*", c));
1947 /* --------------------------------------------------------------------------------------------- */
1948 /** inserts a file at the cursor, returns count of inserted bytes on success */
1950 off_t
1951 edit_insert_file (WEdit * edit, const vfs_path_t * filename_vpath)
1953 char *p;
1954 off_t current;
1955 off_t ins_len = 0;
1957 p = edit_get_filter (filename_vpath);
1958 current = edit->buffer.curs1;
1960 if (p != NULL)
1962 FILE *f;
1964 f = (FILE *) popen (p, "r");
1965 if (f != NULL)
1967 edit_insert_stream (edit, f);
1969 /* Place cursor at the end of text selection */
1970 if (!option_cursor_after_inserted_block)
1972 ins_len = edit->buffer.curs1 - current;
1973 edit_cursor_move (edit, -ins_len);
1975 if (pclose (f) > 0)
1977 char *errmsg;
1979 errmsg = g_strdup_printf (_("Error reading from pipe: %s"), p);
1980 edit_error_dialog (_("Error"), errmsg);
1981 g_free (errmsg);
1982 ins_len = -1;
1985 else
1987 char *errmsg;
1989 errmsg = g_strdup_printf (_("Cannot open pipe for reading: %s"), p);
1990 edit_error_dialog (_("Error"), errmsg);
1991 g_free (errmsg);
1992 ins_len = -1;
1994 g_free (p);
1996 else
1998 int file;
1999 off_t blocklen;
2000 int vertical_insertion = 0;
2001 char *buf;
2003 file = mc_open (filename_vpath, O_RDONLY | O_BINARY);
2004 if (file == -1)
2005 return -1;
2007 buf = g_malloc0 (TEMP_BUF_LEN);
2008 blocklen = mc_read (file, buf, sizeof (VERTICAL_MAGIC));
2009 if (blocklen > 0)
2011 /* if contain signature VERTICAL_MAGIC then it vertical block */
2012 if (memcmp (buf, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC)) == 0)
2013 vertical_insertion = 1;
2014 else
2015 mc_lseek (file, 0, SEEK_SET);
2018 if (vertical_insertion)
2020 off_t mark1, mark2;
2021 long c1, c2;
2023 blocklen = edit_insert_column_from_file (edit, file, &mark1, &mark2, &c1, &c2);
2024 edit_set_markers (edit, edit->buffer.curs1, mark2, c1, c2);
2026 /* highlight inserted text then not persistent blocks */
2027 if (!option_persistent_selections && edit->modified)
2029 if (!edit->column_highlight)
2030 edit_push_undo_action (edit, COLUMN_OFF);
2031 edit->column_highlight = 1;
2034 else
2036 off_t i;
2038 while ((blocklen = mc_read (file, (char *) buf, TEMP_BUF_LEN)) > 0)
2040 for (i = 0; i < blocklen; i++)
2041 edit_insert (edit, buf[i]);
2043 /* highlight inserted text then not persistent blocks */
2044 if (!option_persistent_selections && edit->modified)
2046 edit_set_markers (edit, edit->buffer.curs1, current, 0, 0);
2047 if (edit->column_highlight)
2048 edit_push_undo_action (edit, COLUMN_ON);
2049 edit->column_highlight = 0;
2052 /* Place cursor at the end of text selection */
2053 if (!option_cursor_after_inserted_block)
2055 ins_len = edit->buffer.curs1 - current;
2056 edit_cursor_move (edit, -ins_len);
2060 edit->force |= REDRAW_PAGE;
2061 g_free (buf);
2062 mc_close (file);
2063 if (blocklen != 0)
2064 ins_len = 0;
2067 return ins_len;
2070 /* --------------------------------------------------------------------------------------------- */
2072 * Fill in the edit structure. Return NULL on failure. Pass edit as
2073 * NULL to allocate a new structure.
2075 * If line is 0, try to restore saved position. Otherwise put the
2076 * cursor on that line and show it in the middle of the screen.
2079 WEdit *
2080 edit_init (WEdit * edit, int y, int x, int lines, int cols, const vfs_path_t * filename_vpath,
2081 long line)
2083 gboolean to_free = FALSE;
2085 option_auto_syntax = TRUE; /* Resetting to auto on every invokation */
2086 option_line_state_width = option_line_state ? LINE_STATE_WIDTH : 0;
2088 if (edit != NULL)
2090 /* save some widget parameters */
2091 gboolean fullscreen = edit->fullscreen;
2092 int y_prev = edit->y_prev;
2093 int x_prev = edit->x_prev;
2094 int lines_prev = edit->lines_prev;
2095 int cols_prev = edit->cols_prev;
2097 edit_purge_widget (edit);
2099 /* restore saved parameters */
2100 edit->fullscreen = fullscreen;
2101 edit->y_prev = y_prev;
2102 edit->x_prev = x_prev;
2103 edit->lines_prev = lines_prev;
2104 edit->cols_prev = cols_prev;
2106 else
2108 Widget *w;
2109 edit = g_malloc0 (sizeof (WEdit));
2110 to_free = TRUE;
2112 w = WIDGET (edit);
2113 widget_init (w, y, x, lines, cols, NULL, NULL);
2114 w->options |= WOP_SELECTABLE | WOP_TOP_SELECT | WOP_WANT_CURSOR;
2115 edit->fullscreen = TRUE;
2116 edit_save_size (edit);
2119 edit->drag_state = MCEDIT_DRAG_NONE;
2121 edit->stat1.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
2122 edit->stat1.st_uid = getuid ();
2123 edit->stat1.st_gid = getgid ();
2124 edit->stat1.st_mtime = 0;
2126 edit->over_col = 0;
2127 edit->bracket = -1;
2128 edit->last_bracket = -1;
2129 edit->force |= REDRAW_PAGE;
2131 /* set file name before load file */
2132 edit_set_filename (edit, filename_vpath);
2134 edit->undo_stack_size = START_STACK_SIZE;
2135 edit->undo_stack_size_mask = START_STACK_SIZE - 1;
2136 edit->undo_stack = g_malloc0 ((edit->undo_stack_size + 10) * sizeof (long));
2138 edit->redo_stack_size = START_STACK_SIZE;
2139 edit->redo_stack_size_mask = START_STACK_SIZE - 1;
2140 edit->redo_stack = g_malloc0 ((edit->redo_stack_size + 10) * sizeof (long));
2142 #ifdef HAVE_CHARSET
2143 edit->utf8 = FALSE;
2144 edit->converter = str_cnv_from_term;
2145 edit_set_codeset (edit);
2146 #endif
2148 if (!edit_load_file (edit))
2150 /* edit_load_file already gives an error message */
2151 if (to_free)
2152 g_free (edit);
2153 return NULL;
2156 edit->loading_done = 1;
2157 edit->modified = 0;
2158 edit->locked = 0;
2159 edit_load_syntax (edit, NULL, NULL);
2160 edit_get_syntax_color (edit, -1);
2162 /* load saved cursor position and/or boolmarks */
2163 if ((line == 0) && option_save_position)
2164 edit_load_position (edit, TRUE);
2165 else
2167 edit_load_position (edit, FALSE);
2168 if (line <= 0)
2169 line = 1;
2170 edit_move_display (edit, line - 1);
2171 edit_move_to_line (edit, line - 1);
2174 edit_load_macro_cmd (edit);
2176 return edit;
2179 /* --------------------------------------------------------------------------------------------- */
2181 /** Clear the edit struct, freeing everything in it. Return TRUE on success */
2182 gboolean
2183 edit_clean (WEdit * edit)
2185 if (edit == NULL)
2186 return FALSE;
2188 /* a stale lock, remove it */
2189 if (edit->locked)
2190 edit->locked = unlock_file (edit->filename_vpath);
2192 /* save cursor position */
2193 if (option_save_position)
2194 edit_save_position (edit);
2195 else if (edit->serialized_bookmarks != NULL)
2196 edit->serialized_bookmarks = (GArray *) g_array_free (edit->serialized_bookmarks, TRUE);
2198 /* File specified on the mcedit command line and never saved */
2199 if (edit->delete_file)
2200 unlink (vfs_path_get_last_path_str (edit->filename_vpath));
2202 edit_free_syntax_rules (edit);
2203 book_mark_flush (edit, -1);
2205 edit_buffer_clean (&edit->buffer);
2207 g_free (edit->undo_stack);
2208 g_free (edit->redo_stack);
2209 vfs_path_free (edit->filename_vpath);
2210 vfs_path_free (edit->dir_vpath);
2211 mc_search_free (edit->search);
2212 edit->search = NULL;
2213 MC_PTR_FREE (edit->last_search_string);
2215 #ifdef HAVE_CHARSET
2216 if (edit->converter != str_cnv_from_term)
2217 str_close_conv (edit->converter);
2218 #endif
2220 edit_purge_widget (edit);
2222 return TRUE;
2225 /* --------------------------------------------------------------------------------------------- */
2228 * Load a new file into the editor and set line. If it fails, preserve the old file.
2229 * To do it, allocate a new widget, initialize it and, if the new file
2230 * was loaded, copy the data to the old widget.
2232 * @return TRUE on success, FALSE on failure.
2234 gboolean
2235 edit_reload_line (WEdit * edit, const vfs_path_t * filename_vpath, long line)
2237 Widget *w = WIDGET (edit);
2238 WEdit *e;
2240 e = g_malloc0 (sizeof (WEdit));
2241 *WIDGET (e) = *w;
2242 /* save some widget parameters */
2243 e->fullscreen = edit->fullscreen;
2244 e->y_prev = edit->y_prev;
2245 e->x_prev = edit->x_prev;
2246 e->lines_prev = edit->lines_prev;
2247 e->cols_prev = edit->cols_prev;
2249 if (edit_init (e, w->y, w->x, w->lines, w->cols, filename_vpath, line) == NULL)
2251 g_free (e);
2252 return FALSE;
2255 edit_clean (edit);
2256 memcpy (edit, e, sizeof (*edit));
2257 g_free (e);
2259 return TRUE;
2262 /* --------------------------------------------------------------------------------------------- */
2264 #ifdef HAVE_CHARSET
2265 void
2266 edit_set_codeset (WEdit * edit)
2268 const char *cp_id;
2270 cp_id =
2271 get_codepage_id (mc_global.source_codepage >=
2272 0 ? mc_global.source_codepage : mc_global.display_codepage);
2274 if (cp_id != NULL)
2276 GIConv conv;
2277 conv = str_crt_conv_from (cp_id);
2278 if (conv != INVALID_CONV)
2280 if (edit->converter != str_cnv_from_term)
2281 str_close_conv (edit->converter);
2282 edit->converter = conv;
2286 if (cp_id != NULL)
2287 edit->utf8 = str_isutf8 (cp_id);
2289 #endif
2291 /* --------------------------------------------------------------------------------------------- */
2294 * Recording stack for undo:
2295 * The following is an implementation of a compressed stack. Identical
2296 * pushes are recorded by a negative prefix indicating the number of times the
2297 * same char was pushed. This saves space for repeated curs-left or curs-right
2298 * delete etc.
2300 * eg:
2302 * pushed: stored:
2305 * b a
2306 * b -3
2307 * b b
2308 * c --> -4
2309 * c c
2310 * c d
2314 * If the stack long int is 0-255 it represents a normal insert (from a backspace),
2315 * 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
2316 * of the cursor functions define'd in edit-impl.h. 1000 through 700'000'000 is to
2317 * set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
2318 * position.
2320 * The only way the cursor moves or the buffer is changed is through the routines:
2321 * insert, backspace, insert_ahead, delete, and cursor_move.
2322 * These record the reverse undo movements onto the stack each time they are
2323 * called.
2325 * Each key press results in a set of actions (insert; delete ...). So each time
2326 * a key is pressed the current position of start_display is pushed as
2327 * KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
2328 * over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
2329 * tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
2333 * @param edit editor object
2334 * @param c code of the action
2337 void
2338 edit_push_undo_action (WEdit * edit, long c)
2340 unsigned long sp = edit->undo_stack_pointer;
2341 unsigned long spm1;
2342 long *t;
2344 /* first enlarge the stack if necessary */
2345 if (sp > edit->undo_stack_size - 10)
2346 { /* say */
2347 if (option_max_undo < 256)
2348 option_max_undo = 256;
2349 if (edit->undo_stack_size < (unsigned long) option_max_undo)
2351 t = g_realloc (edit->undo_stack, (edit->undo_stack_size * 2 + 10) * sizeof (long));
2352 if (t)
2354 edit->undo_stack = t;
2355 edit->undo_stack_size <<= 1;
2356 edit->undo_stack_size_mask = edit->undo_stack_size - 1;
2360 spm1 = (edit->undo_stack_pointer - 1) & edit->undo_stack_size_mask;
2361 if (edit->undo_stack_disable)
2363 edit_push_redo_action (edit, KEY_PRESS);
2364 edit_push_redo_action (edit, c);
2365 return;
2368 if (edit->redo_stack_reset)
2369 edit->redo_stack_bottom = edit->redo_stack_pointer = 0;
2371 if (edit->undo_stack_bottom != sp
2372 && spm1 != edit->undo_stack_bottom
2373 && ((sp - 2) & edit->undo_stack_size_mask) != edit->undo_stack_bottom)
2375 long d;
2376 if (edit->undo_stack[spm1] < 0)
2378 d = edit->undo_stack[(sp - 2) & edit->undo_stack_size_mask];
2379 if (d == c && edit->undo_stack[spm1] > -1000000000)
2381 if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
2382 edit->undo_stack[spm1]--;
2383 return;
2386 else
2388 d = edit->undo_stack[spm1];
2389 if (d == c)
2391 if (c >= KEY_PRESS)
2392 return; /* --> no need to push multiple do-nothings */
2393 edit->undo_stack[sp] = -2;
2394 goto check_bottom;
2398 edit->undo_stack[sp] = c;
2400 check_bottom:
2401 edit->undo_stack_pointer = (edit->undo_stack_pointer + 1) & edit->undo_stack_size_mask;
2403 /* if the sp wraps round and catches the undo_stack_bottom then erase
2404 * the first set of actions on the stack to make space - by moving
2405 * undo_stack_bottom forward one "key press" */
2406 c = (edit->undo_stack_pointer + 2) & edit->undo_stack_size_mask;
2407 if ((unsigned long) c == edit->undo_stack_bottom ||
2408 (((unsigned long) c + 1) & edit->undo_stack_size_mask) == edit->undo_stack_bottom)
2411 edit->undo_stack_bottom = (edit->undo_stack_bottom + 1) & edit->undo_stack_size_mask;
2413 while (edit->undo_stack[edit->undo_stack_bottom] < KEY_PRESS
2414 && edit->undo_stack_bottom != edit->undo_stack_pointer);
2416 /*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: */
2417 if (edit->undo_stack_pointer != edit->undo_stack_bottom
2418 && edit->undo_stack[edit->undo_stack_bottom] < KEY_PRESS)
2420 edit->undo_stack_bottom = edit->undo_stack_pointer = 0;
2424 /* --------------------------------------------------------------------------------------------- */
2426 void
2427 edit_push_redo_action (WEdit * edit, long c)
2429 unsigned long sp = edit->redo_stack_pointer;
2430 unsigned long spm1;
2431 long *t;
2432 /* first enlarge the stack if necessary */
2433 if (sp > edit->redo_stack_size - 10)
2434 { /* say */
2435 if (option_max_undo < 256)
2436 option_max_undo = 256;
2437 if (edit->redo_stack_size < (unsigned long) option_max_undo)
2439 t = g_realloc (edit->redo_stack, (edit->redo_stack_size * 2 + 10) * sizeof (long));
2440 if (t)
2442 edit->redo_stack = t;
2443 edit->redo_stack_size <<= 1;
2444 edit->redo_stack_size_mask = edit->redo_stack_size - 1;
2448 spm1 = (edit->redo_stack_pointer - 1) & edit->redo_stack_size_mask;
2450 if (edit->redo_stack_bottom != sp
2451 && spm1 != edit->redo_stack_bottom
2452 && ((sp - 2) & edit->redo_stack_size_mask) != edit->redo_stack_bottom)
2454 long d;
2455 if (edit->redo_stack[spm1] < 0)
2457 d = edit->redo_stack[(sp - 2) & edit->redo_stack_size_mask];
2458 if (d == c && edit->redo_stack[spm1] > -1000000000)
2460 if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
2461 edit->redo_stack[spm1]--;
2462 return;
2465 else
2467 d = edit->redo_stack[spm1];
2468 if (d == c)
2470 if (c >= KEY_PRESS)
2471 return; /* --> no need to push multiple do-nothings */
2472 edit->redo_stack[sp] = -2;
2473 goto redo_check_bottom;
2477 edit->redo_stack[sp] = c;
2479 redo_check_bottom:
2480 edit->redo_stack_pointer = (edit->redo_stack_pointer + 1) & edit->redo_stack_size_mask;
2482 /* if the sp wraps round and catches the redo_stack_bottom then erase
2483 * the first set of actions on the stack to make space - by moving
2484 * redo_stack_bottom forward one "key press" */
2485 c = (edit->redo_stack_pointer + 2) & edit->redo_stack_size_mask;
2486 if ((unsigned long) c == edit->redo_stack_bottom ||
2487 (((unsigned long) c + 1) & edit->redo_stack_size_mask) == edit->redo_stack_bottom)
2490 edit->redo_stack_bottom = (edit->redo_stack_bottom + 1) & edit->redo_stack_size_mask;
2492 while (edit->redo_stack[edit->redo_stack_bottom] < KEY_PRESS
2493 && edit->redo_stack_bottom != edit->redo_stack_pointer);
2496 * If a single key produced enough pushes to wrap all the way round then
2497 * we would notice that the [redo_stack_bottom] does not contain KEY_PRESS.
2498 * The stack is then initialised:
2501 if (edit->redo_stack_pointer != edit->redo_stack_bottom
2502 && edit->redo_stack[edit->redo_stack_bottom] < KEY_PRESS)
2503 edit->redo_stack_bottom = edit->redo_stack_pointer = 0;
2506 /* --------------------------------------------------------------------------------------------- */
2508 Basic low level single character buffer alterations and movements at the cursor.
2511 void
2512 edit_insert (WEdit * edit, int c)
2514 /* first we must update the position of the display window */
2515 if (edit->buffer.curs1 < edit->start_display)
2517 edit->start_display++;
2518 if (c == '\n')
2519 edit->start_line++;
2522 /* Mark file as modified, unless the file hasn't been fully loaded */
2523 if (edit->loading_done)
2524 edit_modification (edit);
2526 /* now we must update some info on the file and check if a redraw is required */
2527 if (c == '\n')
2529 book_mark_inc (edit, edit->buffer.curs_line);
2530 edit->buffer.curs_line++;
2531 edit->buffer.lines++;
2532 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
2535 /* save the reverse command onto the undo stack */
2536 /* ordinary char and not space */
2537 if (c > 32)
2538 edit_push_undo_action (edit, BACKSPACE);
2539 else
2540 edit_push_undo_action (edit, BACKSPACE_BR);
2541 /* update markers */
2542 edit->mark1 += (edit->mark1 > edit->buffer.curs1) ? 1 : 0;
2543 edit->mark2 += (edit->mark2 > edit->buffer.curs1) ? 1 : 0;
2544 edit->last_get_rule += (edit->last_get_rule > edit->buffer.curs1) ? 1 : 0;
2546 edit_buffer_insert (&edit->buffer, c);
2549 /* --------------------------------------------------------------------------------------------- */
2550 /** same as edit_insert and move left */
2552 void
2553 edit_insert_ahead (WEdit * edit, int c)
2555 if (edit->buffer.curs1 < edit->start_display)
2557 edit->start_display++;
2558 if (c == '\n')
2559 edit->start_line++;
2561 edit_modification (edit);
2562 if (c == '\n')
2564 book_mark_inc (edit, edit->buffer.curs_line);
2565 edit->buffer.lines++;
2566 edit->force |= REDRAW_AFTER_CURSOR;
2568 /* ordinary char and not space */
2569 if (c > 32)
2570 edit_push_undo_action (edit, DELCHAR);
2571 else
2572 edit_push_undo_action (edit, DELCHAR_BR);
2574 edit->mark1 += (edit->mark1 >= edit->buffer.curs1) ? 1 : 0;
2575 edit->mark2 += (edit->mark2 >= edit->buffer.curs1) ? 1 : 0;
2576 edit->last_get_rule += (edit->last_get_rule >= edit->buffer.curs1) ? 1 : 0;
2578 edit_buffer_insert_ahead (&edit->buffer, c);
2581 /* --------------------------------------------------------------------------------------------- */
2583 void
2584 edit_insert_over (WEdit * edit)
2586 long i;
2588 for (i = 0; i < edit->over_col; i++)
2589 edit_insert (edit, ' ');
2591 edit->over_col = 0;
2594 /* --------------------------------------------------------------------------------------------- */
2597 edit_delete (WEdit * edit, gboolean byte_delete)
2599 int p = 0;
2600 int char_length = 1;
2601 int i;
2603 if (edit->buffer.curs2 == 0)
2604 return 0;
2606 #ifdef HAVE_CHARSET
2607 /* if byte_delete == TRUE then delete only one byte not multibyte char */
2608 if (edit->utf8 && !byte_delete)
2610 edit_buffer_get_utf (&edit->buffer, edit->buffer.curs1, &char_length);
2611 if (char_length < 1)
2612 char_length = 1;
2614 #else
2615 (void) byte_delete;
2616 #endif
2618 if (edit->mark2 != edit->mark1)
2619 edit_push_markers (edit);
2621 for (i = 1; i <= char_length; i++)
2623 if (edit->mark1 > edit->buffer.curs1)
2625 edit->mark1--;
2626 edit->end_mark_curs--;
2628 if (edit->mark2 > edit->buffer.curs1)
2629 edit->mark2--;
2630 if (edit->last_get_rule > edit->buffer.curs1)
2631 edit->last_get_rule--;
2633 p = edit_buffer_delete (&edit->buffer);
2635 edit_push_undo_action (edit, p + 256);
2638 edit_modification (edit);
2639 if (p == '\n')
2641 book_mark_dec (edit, edit->buffer.curs_line);
2642 edit->buffer.lines--;
2643 edit->force |= REDRAW_AFTER_CURSOR;
2645 if (edit->buffer.curs1 < edit->start_display)
2647 edit->start_display--;
2648 if (p == '\n')
2649 edit->start_line--;
2652 return p;
2655 /* --------------------------------------------------------------------------------------------- */
2658 edit_backspace (WEdit * edit, gboolean byte_delete)
2660 int p = 0;
2661 int char_length = 1;
2662 int i;
2664 if (edit->buffer.curs1 == 0)
2665 return 0;
2667 if (edit->mark2 != edit->mark1)
2668 edit_push_markers (edit);
2670 #ifdef HAVE_CHARSET
2671 if (edit->utf8 && !byte_delete)
2673 edit_buffer_get_prev_utf (&edit->buffer, edit->buffer.curs1, &char_length);
2674 if (char_length < 1)
2675 char_length = 1;
2677 #else
2678 (void) byte_delete;
2679 #endif
2681 for (i = 1; i <= char_length; i++)
2683 if (edit->mark1 >= edit->buffer.curs1)
2685 edit->mark1--;
2686 edit->end_mark_curs--;
2688 if (edit->mark2 >= edit->buffer.curs1)
2689 edit->mark2--;
2690 if (edit->last_get_rule >= edit->buffer.curs1)
2691 edit->last_get_rule--;
2693 p = edit_buffer_backspace (&edit->buffer);
2695 edit_push_undo_action (edit, p);
2697 edit_modification (edit);
2698 if (p == '\n')
2700 book_mark_dec (edit, edit->buffer.curs_line);
2701 edit->buffer.curs_line--;
2702 edit->buffer.lines--;
2703 edit->force |= REDRAW_AFTER_CURSOR;
2706 if (edit->buffer.curs1 < edit->start_display)
2708 edit->start_display--;
2709 if (p == '\n')
2710 edit->start_line--;
2713 return p;
2716 /* --------------------------------------------------------------------------------------------- */
2717 /** moves the cursor right or left: increment positive or negative respectively */
2719 void
2720 edit_cursor_move (WEdit * edit, off_t increment)
2722 if (increment < 0)
2724 for (; increment < 0 && edit->buffer.curs1 != 0; increment++)
2726 int c;
2728 edit_push_undo_action (edit, CURS_RIGHT);
2730 c = edit_buffer_get_previous_byte (&edit->buffer);
2731 edit_buffer_insert_ahead (&edit->buffer, c);
2732 c = edit_buffer_backspace (&edit->buffer);
2733 if (c == '\n')
2735 edit->buffer.curs_line--;
2736 edit->force |= REDRAW_LINE_BELOW;
2740 else
2742 for (; increment > 0 && edit->buffer.curs2 != 0; increment--)
2744 int c;
2746 edit_push_undo_action (edit, CURS_LEFT);
2748 c = edit_buffer_get_current_byte (&edit->buffer);
2749 edit_buffer_insert (&edit->buffer, c);
2750 c = edit_buffer_delete (&edit->buffer);
2751 if (c == '\n')
2753 edit->buffer.curs_line++;
2754 edit->force |= REDRAW_LINE_ABOVE;
2760 /* --------------------------------------------------------------------------------------------- */
2761 /* If cols is zero this returns the count of columns from current to upto. */
2762 /* If upto is zero returns index of cols across from current. */
2764 off_t
2765 edit_move_forward3 (const WEdit * edit, off_t current, long cols, off_t upto)
2767 off_t p, q;
2768 long col;
2770 if (upto != 0)
2772 q = upto;
2773 cols = -10;
2775 else
2776 q = edit->buffer.size + 2;
2778 for (col = 0, p = current; p < q; p++)
2780 int c, orig_c;
2782 if (cols != -10)
2784 if (col == cols)
2785 return p;
2786 if (col > cols)
2787 return p - 1;
2790 orig_c = c = edit_buffer_get_byte (&edit->buffer, p);
2792 #ifdef HAVE_CHARSET
2793 if (edit->utf8)
2795 int utf_ch;
2796 int char_length = 1;
2798 utf_ch = edit_buffer_get_utf (&edit->buffer, p, &char_length);
2799 if (mc_global.utf8_display)
2801 if (char_length > 1)
2802 col -= char_length - 1;
2803 if (g_unichar_iswide (utf_ch))
2804 col++;
2806 else if (char_length > 1 && g_unichar_isprint (utf_ch))
2807 col -= char_length - 1;
2810 c = convert_to_display_c (c);
2811 #endif
2813 if (c == '\n')
2814 return (upto != 0 ? (off_t) col : p);
2815 if (c == '\t')
2816 col += TAB_SIZE - col % TAB_SIZE;
2817 else if ((c < 32 || c == 127) && (orig_c == c
2818 #ifdef HAVE_CHARSET
2819 || (!mc_global.utf8_display && !edit->utf8)
2820 #endif
2822 /* '\r' is shown as ^M, so we must advance 2 characters */
2823 /* Caret notation for control characters */
2824 col += 2;
2825 else
2826 col++;
2828 return (off_t) col;
2831 /* --------------------------------------------------------------------------------------------- */
2832 /** returns the current column position of the cursor */
2834 long
2835 edit_get_col (const WEdit * edit)
2837 return (long) edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), 0,
2838 edit->buffer.curs1);
2841 /* --------------------------------------------------------------------------------------------- */
2842 /* Scrolling functions */
2843 /* --------------------------------------------------------------------------------------------- */
2845 void
2846 edit_update_curs_row (WEdit * edit)
2848 edit->curs_row = edit->buffer.curs_line - edit->start_line;
2851 /* --------------------------------------------------------------------------------------------- */
2853 void
2854 edit_update_curs_col (WEdit * edit)
2856 edit->curs_col = (long) edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer),
2857 0, edit->buffer.curs1);
2860 /* --------------------------------------------------------------------------------------------- */
2862 long
2863 edit_get_curs_col (const WEdit * edit)
2865 return edit->curs_col;
2868 /* --------------------------------------------------------------------------------------------- */
2869 /** moves the display start position up by i lines */
2871 void
2872 edit_scroll_upward (WEdit * edit, long i)
2874 long lines_above = edit->start_line;
2876 if (i > lines_above)
2877 i = lines_above;
2878 if (i != 0)
2880 edit->start_line -= i;
2881 edit->start_display =
2882 edit_buffer_get_backward_offset (&edit->buffer, edit->start_display, i);
2883 edit->force |= REDRAW_PAGE;
2884 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
2886 edit_update_curs_row (edit);
2890 /* --------------------------------------------------------------------------------------------- */
2892 void
2893 edit_scroll_downward (WEdit * edit, long i)
2895 long lines_below;
2897 lines_below = edit->buffer.lines - edit->start_line - (WIDGET (edit)->lines - 1);
2898 if (lines_below > 0)
2900 if (i > lines_below)
2901 i = lines_below;
2902 edit->start_line += i;
2903 edit->start_display =
2904 edit_buffer_get_forward_offset (&edit->buffer, edit->start_display, i, 0);
2905 edit->force |= REDRAW_PAGE;
2906 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
2908 edit_update_curs_row (edit);
2911 /* --------------------------------------------------------------------------------------------- */
2913 void
2914 edit_scroll_right (WEdit * edit, long i)
2916 edit->force |= REDRAW_PAGE;
2917 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
2918 edit->start_col -= i;
2921 /* --------------------------------------------------------------------------------------------- */
2923 void
2924 edit_scroll_left (WEdit * edit, long i)
2926 if (edit->start_col)
2928 edit->start_col += i;
2929 if (edit->start_col > 0)
2930 edit->start_col = 0;
2931 edit->force |= REDRAW_PAGE;
2932 edit->force &= (0xfff - REDRAW_CHAR_ONLY);
2936 /* --------------------------------------------------------------------------------------------- */
2937 /* high level cursor movement commands */
2938 /* --------------------------------------------------------------------------------------------- */
2940 void
2941 edit_move_to_prev_col (WEdit * edit, off_t p)
2943 long prev = edit->prev_col;
2944 long over = edit->over_col;
2946 edit_cursor_move (edit,
2947 edit_move_forward3 (edit, p, prev + edit->over_col, 0) - edit->buffer.curs1);
2949 if (option_cursor_beyond_eol)
2951 long line_len;
2953 line_len = (long) edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), 0,
2954 edit_buffer_get_current_eol (&edit->buffer));
2955 if (line_len < prev + edit->over_col)
2957 edit->over_col = prev + over - line_len;
2958 edit->prev_col = line_len;
2959 edit->curs_col = line_len;
2961 else
2963 edit->curs_col = prev + over;
2964 edit->prev_col = edit->curs_col;
2965 edit->over_col = 0;
2968 else
2970 edit->over_col = 0;
2971 if (option_fake_half_tabs && is_in_indent (&edit->buffer))
2973 long fake_half_tabs;
2975 edit_update_curs_col (edit);
2977 fake_half_tabs = HALF_TAB_SIZE * space_width;
2978 if (fake_half_tabs != 0 && edit->curs_col % fake_half_tabs != 0)
2980 long q;
2982 q = edit->curs_col;
2983 edit->curs_col -= (edit->curs_col % fake_half_tabs);
2984 p = edit_buffer_get_current_bol (&edit->buffer);
2985 edit_cursor_move (edit,
2986 edit_move_forward3 (edit, p, edit->curs_col,
2987 0) - edit->buffer.curs1);
2988 if (!left_of_four_spaces (edit))
2989 edit_cursor_move (edit,
2990 edit_move_forward3 (edit, p, q, 0) - edit->buffer.curs1);
2996 /* --------------------------------------------------------------------------------------------- */
2997 /** check whether line in editor is blank or not
2999 * @param edit editor object
3000 * @param line number of line
3002 * @return TRUE if line in blank, FALSE otherwise
3005 gboolean
3006 edit_line_is_blank (WEdit * edit, long line)
3008 return is_blank (&edit->buffer, edit_find_line (edit, line));
3011 /* --------------------------------------------------------------------------------------------- */
3012 /** move cursor to line 'line' */
3014 void
3015 edit_move_to_line (WEdit * e, long line)
3017 if (line < e->buffer.curs_line)
3018 edit_move_up (e, e->buffer.curs_line - line, FALSE);
3019 else
3020 edit_move_down (e, line - e->buffer.curs_line, FALSE);
3021 edit_scroll_screen_over_cursor (e);
3024 /* --------------------------------------------------------------------------------------------- */
3025 /** scroll window so that first visible line is 'line' */
3027 void
3028 edit_move_display (WEdit * e, long line)
3030 if (line < e->start_line)
3031 edit_scroll_upward (e, e->start_line - line);
3032 else
3033 edit_scroll_downward (e, line - e->start_line);
3036 /* --------------------------------------------------------------------------------------------- */
3037 /** save markers onto undo stack */
3039 void
3040 edit_push_markers (WEdit * edit)
3042 edit_push_undo_action (edit, MARK_1 + edit->mark1);
3043 edit_push_undo_action (edit, MARK_2 + edit->mark2);
3044 edit_push_undo_action (edit, MARK_CURS + edit->end_mark_curs);
3047 /* --------------------------------------------------------------------------------------------- */
3049 void
3050 edit_set_markers (WEdit * edit, off_t m1, off_t m2, long c1, long c2)
3052 edit->mark1 = m1;
3053 edit->mark2 = m2;
3054 edit->column1 = c1;
3055 edit->column2 = c2;
3059 /* --------------------------------------------------------------------------------------------- */
3060 /** highlight marker toggle */
3062 void
3063 edit_mark_cmd (WEdit * edit, gboolean unmark)
3065 edit_push_markers (edit);
3066 if (unmark)
3068 edit_set_markers (edit, 0, 0, 0, 0);
3069 edit->force |= REDRAW_PAGE;
3071 else if (edit->mark2 >= 0)
3073 edit->end_mark_curs = -1;
3074 edit_set_markers (edit, edit->buffer.curs1, -1, edit->curs_col + edit->over_col,
3075 edit->curs_col + edit->over_col);
3076 edit->force |= REDRAW_PAGE;
3078 else
3080 edit->end_mark_curs = edit->buffer.curs1;
3081 edit_set_markers (edit, edit->mark1, edit->buffer.curs1, edit->column1,
3082 edit->curs_col + edit->over_col);
3086 /* --------------------------------------------------------------------------------------------- */
3087 /** highlight the word under cursor */
3089 void
3090 edit_mark_current_word_cmd (WEdit * edit)
3092 long pos;
3094 for (pos = edit->buffer.curs1; pos != 0; pos--)
3096 int c1, c2;
3098 c1 = edit_buffer_get_byte (&edit->buffer, pos);
3099 c2 = edit_buffer_get_byte (&edit->buffer, pos - 1);
3100 if (!isspace (c1) && isspace (c2))
3101 break;
3102 if ((my_type_of (c1) & my_type_of (c2)) == 0)
3103 break;
3105 edit->mark1 = pos;
3107 for (; pos < edit->buffer.size; pos++)
3109 int c1, c2;
3111 c1 = edit_buffer_get_byte (&edit->buffer, pos);
3112 c2 = edit_buffer_get_byte (&edit->buffer, pos + 1);
3113 if (!isspace (c1) && isspace (c2))
3114 break;
3115 if ((my_type_of (c1) & my_type_of (c2)) == 0)
3116 break;
3118 edit->mark2 = MIN (pos + 1, edit->buffer.size);
3120 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
3123 /* --------------------------------------------------------------------------------------------- */
3125 void
3126 edit_mark_current_line_cmd (WEdit * edit)
3128 edit->mark1 = edit_buffer_get_current_bol (&edit->buffer);
3129 edit->mark2 = edit_buffer_get_current_eol (&edit->buffer);
3131 edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
3134 /* --------------------------------------------------------------------------------------------- */
3136 void
3137 edit_delete_line (WEdit * edit)
3140 * Delete right part of the line.
3141 * Note that edit_buffer_get_byte() returns '\n' when byte position is
3142 * beyond EOF.
3144 while (edit_buffer_get_current_byte (&edit->buffer) != '\n')
3145 (void) edit_delete (edit, TRUE);
3148 * Delete '\n' char.
3149 * Note that edit_delete() will not corrupt anything if called while
3150 * cursor position is EOF.
3152 (void) edit_delete (edit, TRUE);
3155 * Delete left part of the line.
3156 * Note, that edit_buffer_get_byte() returns '\n' when byte position is < 0.
3158 while (edit_buffer_get_previous_byte (&edit->buffer) != '\n')
3159 (void) edit_backspace (edit, TRUE);
3162 /* --------------------------------------------------------------------------------------------- */
3164 void
3165 edit_push_key_press (WEdit * edit)
3167 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
3168 if (edit->mark2 == -1)
3170 edit_push_undo_action (edit, MARK_1 + edit->mark1);
3171 edit_push_undo_action (edit, MARK_CURS + edit->end_mark_curs);
3175 /* --------------------------------------------------------------------------------------------- */
3177 void
3178 edit_find_bracket (WEdit * edit)
3180 edit->bracket = edit_get_bracket (edit, 1, 10000);
3181 if (edit->last_bracket != edit->bracket)
3182 edit->force |= REDRAW_PAGE;
3183 edit->last_bracket = edit->bracket;
3186 /* --------------------------------------------------------------------------------------------- */
3188 * This executes a command as though the user initiated it through a key
3189 * press. Callback with MSG_KEY as a message calls this after
3190 * translating the key press. This function can be used to pass any
3191 * command to the editor. Note that the screen wouldn't update
3192 * automatically. Either of command or char_for_insertion must be
3193 * passed as -1. Commands are executed, and char_for_insertion is
3194 * inserted at the cursor.
3197 void
3198 edit_execute_key_command (WEdit * edit, long command, int char_for_insertion)
3200 if (command == CK_MacroStartRecord || command == CK_RepeatStartRecord
3201 || (macro_index < 0
3202 && (command == CK_MacroStartStopRecord || command == CK_RepeatStartStopRecord)))
3204 macro_index = 0;
3205 edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
3206 return;
3208 if (macro_index != -1)
3210 edit->force |= REDRAW_COMPLETELY;
3211 if (command == CK_MacroStopRecord || command == CK_MacroStartStopRecord)
3213 edit_store_macro_cmd (edit);
3214 macro_index = -1;
3215 return;
3217 if (command == CK_RepeatStopRecord || command == CK_RepeatStartStopRecord)
3219 edit_repeat_macro_cmd (edit);
3220 macro_index = -1;
3221 return;
3225 if (macro_index >= 0 && macro_index < MAX_MACRO_LENGTH - 1)
3227 record_macro_buf[macro_index].action = command;
3228 record_macro_buf[macro_index++].ch = char_for_insertion;
3230 /* record the beginning of a set of editing actions initiated by a key press */
3231 if (command != CK_Undo && command != CK_ExtendedKeyMap)
3232 edit_push_key_press (edit);
3234 edit_execute_cmd (edit, command, char_for_insertion);
3235 if (edit->column_highlight)
3236 edit->force |= REDRAW_PAGE;
3239 /* --------------------------------------------------------------------------------------------- */
3241 This executes a command at a lower level than macro recording.
3242 It also does not push a key_press onto the undo stack. This means
3243 that if it is called many times, a single undo command will undo
3244 all of them. It also does not check for the Undo command.
3246 void
3247 edit_execute_cmd (WEdit * edit, long command, int char_for_insertion)
3249 Widget *w = WIDGET (edit);
3251 if (command == CK_WindowFullscreen)
3253 edit_toggle_fullscreen (edit);
3254 return;
3257 /* handle window state */
3258 if (edit_handle_move_resize (edit, command))
3259 return;
3261 edit->force |= REDRAW_LINE;
3263 /* The next key press will unhighlight the found string, so update
3264 * the whole page */
3265 if (edit->found_len || edit->column_highlight)
3266 edit->force |= REDRAW_PAGE;
3268 switch (command)
3270 /* a mark command with shift-arrow */
3271 case CK_MarkLeft:
3272 case CK_MarkRight:
3273 case CK_MarkToWordBegin:
3274 case CK_MarkToWordEnd:
3275 case CK_MarkToHome:
3276 case CK_MarkToEnd:
3277 case CK_MarkUp:
3278 case CK_MarkDown:
3279 case CK_MarkPageUp:
3280 case CK_MarkPageDown:
3281 case CK_MarkToFileBegin:
3282 case CK_MarkToFileEnd:
3283 case CK_MarkToPageBegin:
3284 case CK_MarkToPageEnd:
3285 case CK_MarkScrollUp:
3286 case CK_MarkScrollDown:
3287 case CK_MarkParagraphUp:
3288 case CK_MarkParagraphDown:
3289 /* a mark command with alt-arrow */
3290 case CK_MarkColumnPageUp:
3291 case CK_MarkColumnPageDown:
3292 case CK_MarkColumnLeft:
3293 case CK_MarkColumnRight:
3294 case CK_MarkColumnUp:
3295 case CK_MarkColumnDown:
3296 case CK_MarkColumnScrollUp:
3297 case CK_MarkColumnScrollDown:
3298 case CK_MarkColumnParagraphUp:
3299 case CK_MarkColumnParagraphDown:
3300 edit->column_highlight = 0;
3301 if (edit->highlight == 0 || (edit->mark2 != -1 && edit->mark1 != edit->mark2))
3303 edit_mark_cmd (edit, TRUE); /* clear */
3304 edit_mark_cmd (edit, FALSE); /* marking on */
3306 edit->highlight = 1;
3307 break;
3309 /* any other command */
3310 default:
3311 if (edit->highlight)
3312 edit_mark_cmd (edit, FALSE); /* clear */
3313 edit->highlight = 0;
3316 /* first check for undo */
3317 if (command == CK_Undo)
3319 edit->redo_stack_reset = 0;
3320 edit_group_undo (edit);
3321 edit->found_len = 0;
3322 edit->prev_col = edit_get_col (edit);
3323 edit->search_start = edit->buffer.curs1;
3324 return;
3326 /* check for redo */
3327 if (command == CK_Redo)
3329 edit->redo_stack_reset = 0;
3330 edit_do_redo (edit);
3331 edit->found_len = 0;
3332 edit->prev_col = edit_get_col (edit);
3333 edit->search_start = edit->buffer.curs1;
3334 return;
3337 edit->redo_stack_reset = 1;
3339 /* An ordinary key press */
3340 if (char_for_insertion >= 0)
3342 /* if non persistent selection and text selected */
3343 if (!option_persistent_selections && edit->mark1 != edit->mark2)
3344 edit_block_delete_cmd (edit);
3346 if (edit->overwrite)
3348 /* remove char only one time, after input first byte, multibyte chars */
3349 #ifdef HAVE_CHARSET
3350 if (!mc_global.utf8_display || edit->charpoint == 0)
3351 #endif
3352 if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
3354 edit_delete (edit, FALSE);
3356 if (option_cursor_beyond_eol && edit->over_col > 0)
3357 edit_insert_over (edit);
3358 #ifdef HAVE_CHARSET
3359 if (char_for_insertion > 255 && !mc_global.utf8_display)
3361 unsigned char str[UTF8_CHAR_LEN + 1];
3362 size_t i = 0;
3363 int res;
3365 res = g_unichar_to_utf8 (char_for_insertion, (char *) str);
3366 if (res == 0)
3368 str[0] = '.';
3369 str[1] = '\0';
3371 else
3373 str[res] = '\0';
3375 while (i <= UTF8_CHAR_LEN && str[i] != '\0')
3377 char_for_insertion = str[i];
3378 edit_insert (edit, char_for_insertion);
3379 i++;
3382 else
3383 #endif
3384 edit_insert (edit, char_for_insertion);
3386 if (option_auto_para_formatting)
3388 format_paragraph (edit, FALSE);
3389 edit->force |= REDRAW_PAGE;
3391 else
3392 check_and_wrap_line (edit);
3393 edit->found_len = 0;
3394 edit->prev_col = edit_get_col (edit);
3395 edit->search_start = edit->buffer.curs1;
3396 edit_find_bracket (edit);
3397 return;
3400 switch (command)
3402 case CK_TopOnScreen:
3403 case CK_BottomOnScreen:
3404 case CK_Top:
3405 case CK_Bottom:
3406 case CK_PageUp:
3407 case CK_PageDown:
3408 case CK_Home:
3409 case CK_End:
3410 case CK_Up:
3411 case CK_Down:
3412 case CK_Left:
3413 case CK_Right:
3414 case CK_WordLeft:
3415 case CK_WordRight:
3416 if (!option_persistent_selections && edit->mark2 >= 0)
3418 if (edit->column_highlight)
3419 edit_push_undo_action (edit, COLUMN_ON);
3420 edit->column_highlight = 0;
3421 edit_mark_cmd (edit, TRUE);
3423 default:
3424 break;
3427 switch (command)
3429 case CK_TopOnScreen:
3430 case CK_BottomOnScreen:
3431 case CK_MarkToPageBegin:
3432 case CK_MarkToPageEnd:
3433 case CK_Up:
3434 case CK_Down:
3435 case CK_WordLeft:
3436 case CK_WordRight:
3437 case CK_MarkToWordBegin:
3438 case CK_MarkToWordEnd:
3439 case CK_MarkUp:
3440 case CK_MarkDown:
3441 case CK_MarkColumnUp:
3442 case CK_MarkColumnDown:
3443 if (edit->mark2 == -1)
3444 break; /*marking is following the cursor: may need to highlight a whole line */
3445 case CK_Left:
3446 case CK_Right:
3447 case CK_MarkLeft:
3448 case CK_MarkRight:
3449 edit->force |= REDRAW_CHAR_ONLY;
3450 default:
3451 break;
3454 /* basic cursor key commands */
3455 switch (command)
3457 case CK_BackSpace:
3458 /* if non persistent selection and text selected */
3459 if (!option_persistent_selections && edit->mark1 != edit->mark2)
3460 edit_block_delete_cmd (edit);
3461 else if (option_cursor_beyond_eol && edit->over_col > 0)
3462 edit->over_col--;
3463 else if (option_backspace_through_tabs && is_in_indent (&edit->buffer))
3465 while (edit_buffer_get_previous_byte (&edit->buffer) != '\n' && edit->buffer.curs1 > 0)
3466 edit_backspace (edit, TRUE);
3468 else if (option_fake_half_tabs && is_in_indent (&edit->buffer)
3469 && right_of_four_spaces (edit))
3471 int i;
3473 for (i = 0; i < HALF_TAB_SIZE; i++)
3474 edit_backspace (edit, TRUE);
3476 else
3477 edit_backspace (edit, FALSE);
3478 break;
3479 case CK_Delete:
3480 /* if non persistent selection and text selected */
3481 if (!option_persistent_selections && edit->mark1 != edit->mark2)
3482 edit_block_delete_cmd (edit);
3483 else
3485 if (option_cursor_beyond_eol && edit->over_col > 0)
3486 edit_insert_over (edit);
3488 if (option_fake_half_tabs && is_in_indent (&edit->buffer) && left_of_four_spaces (edit))
3490 int i;
3492 for (i = 1; i <= HALF_TAB_SIZE; i++)
3493 edit_delete (edit, TRUE);
3495 else
3496 edit_delete (edit, FALSE);
3498 break;
3499 case CK_DeleteToWordBegin:
3500 edit->over_col = 0;
3501 edit_left_delete_word (edit);
3502 break;
3503 case CK_DeleteToWordEnd:
3504 if (option_cursor_beyond_eol && edit->over_col > 0)
3505 edit_insert_over (edit);
3507 edit_right_delete_word (edit);
3508 break;
3509 case CK_DeleteLine:
3510 edit_delete_line (edit);
3511 break;
3512 case CK_DeleteToHome:
3513 edit_delete_to_line_begin (edit);
3514 break;
3515 case CK_DeleteToEnd:
3516 edit_delete_to_line_end (edit);
3517 break;
3518 case CK_Enter:
3519 edit->over_col = 0;
3520 if (option_auto_para_formatting)
3522 edit_double_newline (edit);
3523 if (option_return_does_auto_indent && !bracketed_pasting_in_progress)
3524 edit_auto_indent (edit);
3525 format_paragraph (edit, FALSE);
3527 else
3529 edit_insert (edit, '\n');
3530 if (option_return_does_auto_indent && !bracketed_pasting_in_progress)
3531 edit_auto_indent (edit);
3533 break;
3534 case CK_Return:
3535 edit_insert (edit, '\n');
3536 break;
3538 case CK_MarkColumnPageUp:
3539 edit->column_highlight = 1;
3540 case CK_PageUp:
3541 case CK_MarkPageUp:
3542 edit_move_up (edit, w->lines - 1, TRUE);
3543 break;
3544 case CK_MarkColumnPageDown:
3545 edit->column_highlight = 1;
3546 case CK_PageDown:
3547 case CK_MarkPageDown:
3548 edit_move_down (edit, w->lines - 1, TRUE);
3549 break;
3550 case CK_MarkColumnLeft:
3551 edit->column_highlight = 1;
3552 case CK_Left:
3553 case CK_MarkLeft:
3554 if (option_fake_half_tabs && is_in_indent (&edit->buffer) && right_of_four_spaces (edit))
3556 if (option_cursor_beyond_eol && edit->over_col > 0)
3557 edit->over_col--;
3558 else
3559 edit_cursor_move (edit, -HALF_TAB_SIZE);
3560 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
3562 else
3563 edit_left_char_move_cmd (edit);
3564 break;
3565 case CK_MarkColumnRight:
3566 edit->column_highlight = 1;
3567 case CK_Right:
3568 case CK_MarkRight:
3569 if (option_fake_half_tabs && is_in_indent (&edit->buffer) && left_of_four_spaces (edit))
3571 edit_cursor_move (edit, HALF_TAB_SIZE);
3572 edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
3574 else
3575 edit_right_char_move_cmd (edit);
3576 break;
3577 case CK_TopOnScreen:
3578 case CK_MarkToPageBegin:
3579 edit_begin_page (edit);
3580 break;
3581 case CK_BottomOnScreen:
3582 case CK_MarkToPageEnd:
3583 edit_end_page (edit);
3584 break;
3585 case CK_WordLeft:
3586 case CK_MarkToWordBegin:
3587 edit->over_col = 0;
3588 edit_left_word_move_cmd (edit);
3589 break;
3590 case CK_WordRight:
3591 case CK_MarkToWordEnd:
3592 edit->over_col = 0;
3593 edit_right_word_move_cmd (edit);
3594 break;
3595 case CK_MarkColumnUp:
3596 edit->column_highlight = 1;
3597 case CK_Up:
3598 case CK_MarkUp:
3599 edit_move_up (edit, 1, FALSE);
3600 break;
3601 case CK_MarkColumnDown:
3602 edit->column_highlight = 1;
3603 case CK_Down:
3604 case CK_MarkDown:
3605 edit_move_down (edit, 1, FALSE);
3606 break;
3607 case CK_MarkColumnParagraphUp:
3608 edit->column_highlight = 1;
3609 case CK_ParagraphUp:
3610 case CK_MarkParagraphUp:
3611 edit_move_up_paragraph (edit, FALSE);
3612 break;
3613 case CK_MarkColumnParagraphDown:
3614 edit->column_highlight = 1;
3615 case CK_ParagraphDown:
3616 case CK_MarkParagraphDown:
3617 edit_move_down_paragraph (edit, FALSE);
3618 break;
3619 case CK_MarkColumnScrollUp:
3620 edit->column_highlight = 1;
3621 case CK_ScrollUp:
3622 case CK_MarkScrollUp:
3623 edit_move_up (edit, 1, TRUE);
3624 break;
3625 case CK_MarkColumnScrollDown:
3626 edit->column_highlight = 1;
3627 case CK_ScrollDown:
3628 case CK_MarkScrollDown:
3629 edit_move_down (edit, 1, TRUE);
3630 break;
3631 case CK_Home:
3632 case CK_MarkToHome:
3633 edit_cursor_to_bol (edit);
3634 break;
3635 case CK_End:
3636 case CK_MarkToEnd:
3637 edit_cursor_to_eol (edit);
3638 break;
3639 case CK_Tab:
3640 /* if text marked shift block */
3641 if (edit->mark1 != edit->mark2 && !option_persistent_selections)
3643 if (edit->mark2 < 0)
3644 edit_mark_cmd (edit, FALSE);
3645 edit_move_block_to_right (edit);
3647 else
3649 if (option_cursor_beyond_eol)
3650 edit_insert_over (edit);
3651 edit_tab_cmd (edit);
3652 if (option_auto_para_formatting)
3654 format_paragraph (edit, FALSE);
3655 edit->force |= REDRAW_PAGE;
3657 else
3658 check_and_wrap_line (edit);
3660 break;
3662 case CK_InsertOverwrite:
3663 edit->overwrite = !edit->overwrite;
3664 break;
3666 case CK_Mark:
3667 if (edit->mark2 >= 0)
3669 if (edit->column_highlight)
3670 edit_push_undo_action (edit, COLUMN_ON);
3671 edit->column_highlight = 0;
3673 edit_mark_cmd (edit, FALSE);
3674 break;
3675 case CK_MarkColumn:
3676 if (!edit->column_highlight)
3677 edit_push_undo_action (edit, COLUMN_OFF);
3678 edit->column_highlight = 1;
3679 edit_mark_cmd (edit, FALSE);
3680 break;
3681 case CK_MarkAll:
3682 edit_set_markers (edit, 0, edit->buffer.size, 0, 0);
3683 edit->force |= REDRAW_PAGE;
3684 break;
3685 case CK_Unmark:
3686 if (edit->column_highlight)
3687 edit_push_undo_action (edit, COLUMN_ON);
3688 edit->column_highlight = 0;
3689 edit_mark_cmd (edit, TRUE);
3690 break;
3691 case CK_MarkWord:
3692 if (edit->column_highlight)
3693 edit_push_undo_action (edit, COLUMN_ON);
3694 edit->column_highlight = 0;
3695 edit_mark_current_word_cmd (edit);
3696 break;
3697 case CK_MarkLine:
3698 if (edit->column_highlight)
3699 edit_push_undo_action (edit, COLUMN_ON);
3700 edit->column_highlight = 0;
3701 edit_mark_current_line_cmd (edit);
3702 break;
3704 case CK_Bookmark:
3705 book_mark_clear (edit, edit->buffer.curs_line, BOOK_MARK_FOUND_COLOR);
3706 if (book_mark_query_color (edit, edit->buffer.curs_line, BOOK_MARK_COLOR))
3707 book_mark_clear (edit, edit->buffer.curs_line, BOOK_MARK_COLOR);
3708 else
3709 book_mark_insert (edit, edit->buffer.curs_line, BOOK_MARK_COLOR);
3710 break;
3711 case CK_BookmarkFlush:
3712 book_mark_flush (edit, BOOK_MARK_COLOR);
3713 book_mark_flush (edit, BOOK_MARK_FOUND_COLOR);
3714 edit->force |= REDRAW_PAGE;
3715 break;
3716 case CK_BookmarkNext:
3717 if (edit->book_mark != NULL)
3719 edit_book_mark_t *p;
3721 p = book_mark_find (edit, edit->buffer.curs_line);
3722 if (p->next != NULL)
3724 p = p->next;
3725 if (p->line >= edit->start_line + w->lines || p->line < edit->start_line)
3726 edit_move_display (edit, p->line - w->lines / 2);
3727 edit_move_to_line (edit, p->line);
3730 break;
3731 case CK_BookmarkPrev:
3732 if (edit->book_mark != NULL)
3734 edit_book_mark_t *p;
3736 p = book_mark_find (edit, edit->buffer.curs_line);
3737 while (p->line == edit->buffer.curs_line)
3738 if (p->prev != NULL)
3739 p = p->prev;
3740 if (p->line >= 0)
3742 if (p->line >= edit->start_line + w->lines || p->line < edit->start_line)
3743 edit_move_display (edit, p->line - w->lines / 2);
3744 edit_move_to_line (edit, p->line);
3747 break;
3749 case CK_Top:
3750 case CK_MarkToFileBegin:
3751 edit_move_to_top (edit);
3752 break;
3753 case CK_Bottom:
3754 case CK_MarkToFileEnd:
3755 edit_move_to_bottom (edit);
3756 break;
3758 case CK_Copy:
3759 if (option_cursor_beyond_eol && edit->over_col > 0)
3760 edit_insert_over (edit);
3761 edit_block_copy_cmd (edit);
3762 break;
3763 case CK_Remove:
3764 edit_block_delete_cmd (edit);
3765 break;
3766 case CK_Move:
3767 edit_block_move_cmd (edit);
3768 break;
3770 case CK_BlockShiftLeft:
3771 if (edit->mark1 != edit->mark2)
3772 edit_move_block_to_left (edit);
3773 break;
3774 case CK_BlockShiftRight:
3775 if (edit->mark1 != edit->mark2)
3776 edit_move_block_to_right (edit);
3777 break;
3778 case CK_Store:
3779 edit_copy_to_X_buf_cmd (edit);
3780 break;
3781 case CK_Cut:
3782 edit_cut_to_X_buf_cmd (edit);
3783 break;
3784 case CK_Paste:
3785 /* if non persistent selection and text selected */
3786 if (!option_persistent_selections && edit->mark1 != edit->mark2)
3787 edit_block_delete_cmd (edit);
3788 if (option_cursor_beyond_eol && edit->over_col > 0)
3789 edit_insert_over (edit);
3790 edit_paste_from_X_buf_cmd (edit);
3791 if (!option_persistent_selections && edit->mark2 >= 0)
3793 if (edit->column_highlight)
3794 edit_push_undo_action (edit, COLUMN_ON);
3795 edit->column_highlight = 0;
3796 edit_mark_cmd (edit, TRUE);
3798 break;
3799 case CK_History:
3800 edit_paste_from_history (edit);
3801 break;
3803 case CK_SaveAs:
3804 edit_save_as_cmd (edit);
3805 break;
3806 case CK_Save:
3807 edit_save_confirm_cmd (edit);
3808 break;
3809 case CK_BlockSave:
3810 edit_save_block_cmd (edit);
3811 break;
3812 case CK_InsertFile:
3813 edit_insert_file_cmd (edit);
3814 break;
3816 case CK_FilePrev:
3817 edit_load_back_cmd (edit);
3818 break;
3819 case CK_FileNext:
3820 edit_load_forward_cmd (edit);
3821 break;
3823 case CK_SyntaxChoose:
3824 edit_syntax_dialog (edit);
3825 break;
3827 case CK_Search:
3828 edit_search_cmd (edit, FALSE);
3829 break;
3830 case CK_SearchContinue:
3831 edit_search_cmd (edit, TRUE);
3832 break;
3833 case CK_Replace:
3834 edit_replace_cmd (edit, FALSE);
3835 break;
3836 case CK_ReplaceContinue:
3837 edit_replace_cmd (edit, TRUE);
3838 break;
3839 case CK_Complete:
3840 /* if text marked shift block */
3841 if (edit->mark1 != edit->mark2 && !option_persistent_selections)
3842 edit_move_block_to_left (edit);
3843 else
3844 edit_complete_word_cmd (edit);
3845 break;
3846 case CK_Find:
3847 edit_get_match_keyword_cmd (edit);
3848 break;
3850 #ifdef HAVE_ASPELL
3851 case CK_SpellCheckCurrentWord:
3852 edit_suggest_current_word (edit);
3853 break;
3854 case CK_SpellCheck:
3855 edit_spellcheck_file (edit);
3856 break;
3857 case CK_SpellCheckSelectLang:
3858 edit_set_spell_lang ();
3859 break;
3860 #endif
3862 case CK_Date:
3864 char s[BUF_MEDIUM];
3865 /* fool gcc to prevent a Y2K warning */
3866 char time_format[] = "_c";
3867 time_format[0] = '%';
3869 FMT_LOCALTIME_CURRENT (s, sizeof (s), time_format);
3870 edit_print_string (edit, s);
3871 edit->force |= REDRAW_PAGE;
3873 break;
3874 case CK_Goto:
3875 edit_goto_cmd (edit);
3876 break;
3877 case CK_ParagraphFormat:
3878 format_paragraph (edit, TRUE);
3879 edit->force |= REDRAW_PAGE;
3880 break;
3881 case CK_MacroDelete:
3882 edit_delete_macro_cmd (edit);
3883 break;
3884 case CK_MatchBracket:
3885 edit_goto_matching_bracket (edit);
3886 break;
3887 case CK_UserMenu:
3888 user_menu (edit, NULL, -1);
3889 break;
3890 case CK_Sort:
3891 edit_sort_cmd (edit);
3892 break;
3893 case CK_ExternalCommand:
3894 edit_ext_cmd (edit);
3895 break;
3896 case CK_Mail:
3897 edit_mail_dialog (edit);
3898 break;
3899 #ifdef HAVE_CHARSET
3900 case CK_SelectCodepage:
3901 edit_select_codepage_cmd (edit);
3902 break;
3903 #endif
3904 case CK_InsertLiteral:
3905 edit_insert_literal_cmd (edit);
3906 break;
3907 case CK_MacroStartStopRecord:
3908 edit_begin_end_macro_cmd (edit);
3909 break;
3910 case CK_RepeatStartStopRecord:
3911 edit_begin_end_repeat_cmd (edit);
3912 break;
3913 case CK_ExtendedKeyMap:
3914 edit->extmod = TRUE;
3915 break;
3916 default:
3917 break;
3920 /* CK_PipeBlock */
3921 if ((command / CK_PipeBlock (0)) == 1)
3922 edit_block_process_cmd (edit, command - CK_PipeBlock (0));
3924 /* keys which must set the col position, and the search vars */
3925 switch (command)
3927 case CK_Search:
3928 case CK_SearchContinue:
3929 case CK_Replace:
3930 case CK_ReplaceContinue:
3931 case CK_Complete:
3932 edit->prev_col = edit_get_col (edit);
3933 break;
3934 case CK_Up:
3935 case CK_MarkUp:
3936 case CK_MarkColumnUp:
3937 case CK_Down:
3938 case CK_MarkDown:
3939 case CK_MarkColumnDown:
3940 case CK_PageUp:
3941 case CK_MarkPageUp:
3942 case CK_MarkColumnPageUp:
3943 case CK_PageDown:
3944 case CK_MarkPageDown:
3945 case CK_MarkColumnPageDown:
3946 case CK_Top:
3947 case CK_MarkToFileBegin:
3948 case CK_Bottom:
3949 case CK_MarkToFileEnd:
3950 case CK_ParagraphUp:
3951 case CK_MarkParagraphUp:
3952 case CK_MarkColumnParagraphUp:
3953 case CK_ParagraphDown:
3954 case CK_MarkParagraphDown:
3955 case CK_MarkColumnParagraphDown:
3956 case CK_ScrollUp:
3957 case CK_MarkScrollUp:
3958 case CK_MarkColumnScrollUp:
3959 case CK_ScrollDown:
3960 case CK_MarkScrollDown:
3961 case CK_MarkColumnScrollDown:
3962 edit->search_start = edit->buffer.curs1;
3963 edit->found_len = 0;
3964 break;
3965 default:
3966 edit->found_len = 0;
3967 edit->prev_col = edit_get_col (edit);
3968 edit->search_start = edit->buffer.curs1;
3970 edit_find_bracket (edit);
3972 if (option_auto_para_formatting)
3974 switch (command)
3976 case CK_BackSpace:
3977 case CK_Delete:
3978 case CK_DeleteToWordBegin:
3979 case CK_DeleteToWordEnd:
3980 case CK_DeleteToHome:
3981 case CK_DeleteToEnd:
3982 format_paragraph (edit, FALSE);
3983 edit->force |= REDRAW_PAGE;
3984 default:
3985 break;
3990 /* --------------------------------------------------------------------------------------------- */
3992 void
3993 edit_stack_init (void)
3995 for (edit_stack_iterator = 0; edit_stack_iterator < MAX_HISTORY_MOVETO; edit_stack_iterator++)
3997 edit_history_moveto[edit_stack_iterator].filename_vpath = NULL;
3998 edit_history_moveto[edit_stack_iterator].line = -1;
4001 edit_stack_iterator = 0;
4004 /* --------------------------------------------------------------------------------------------- */
4006 void
4007 edit_stack_free (void)
4009 for (edit_stack_iterator = 0; edit_stack_iterator < MAX_HISTORY_MOVETO; edit_stack_iterator++)
4010 vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath);
4013 /* --------------------------------------------------------------------------------------------- */
4014 /** move i lines */
4016 void
4017 edit_move_up (WEdit * edit, long i, gboolean do_scroll)
4019 edit_move_updown (edit, i, do_scroll, TRUE);
4022 /* --------------------------------------------------------------------------------------------- */
4023 /** move i lines */
4025 void
4026 edit_move_down (WEdit * edit, long i, gboolean do_scroll)
4028 edit_move_updown (edit, i, do_scroll, FALSE);
4031 /* --------------------------------------------------------------------------------------------- */