2 Editor low level data handling and cursor fundamentals.
4 Copyright (C) 1996-2018
5 Free Software Foundation, Inc.
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/>.
29 * \brief Source: editor low level data handling and cursor fundamentals
37 #include <sys/types.h>
43 #include <stdint.h> /* UINTMAX_MAX */
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 */
58 #include "lib/widget.h"
61 #include "lib/charsets.h" /* get_codepage_id */
64 #include "src/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"
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
;
128 { "xz -cd %s 2>&1", "xz > %s", ".xz"},
129 { "zstd -cd %s 2>&1", "zstd > %s", ".zst"},
130 { "lz4 -cd %s 2>&1", "lz4 > %s", ".lz4" },
131 { "lzip -cd %s 2>&1", "lzip > %s", ".lz"},
132 { "lzma -cd %s 2>&1", "lzma > %s", ".lzma" },
133 { "bzip2 -cd %s 2>&1", "bzip2 > %s", ".bz2" },
134 { "gzip -cd %s 2>&1", "gzip > %s", ".gz" },
135 { "gzip -cd %s 2>&1", "gzip > %s", ".Z" }
139 static const off_t option_filesize_default_threshold
= 64 * 1024 * 1024; /* 64 MB */
141 /* --------------------------------------------------------------------------------------------- */
142 /*** file scope functions ************************************************************************/
143 /* --------------------------------------------------------------------------------------------- */
146 edit_load_status_update_cb (status_msg_t
* sm
)
148 simple_status_msg_t
*ssm
= SIMPLE_STATUS_MSG (sm
);
149 edit_buffer_read_file_status_msg_t
*rsm
= (edit_buffer_read_file_status_msg_t
*) sm
;
150 Widget
*wd
= WIDGET (sm
->dlg
);
153 label_set_textv (ssm
->label
, _("Loading: %3d%%"),
154 edit_buffer_calc_percent (rsm
->buf
, rsm
->loaded
));
156 label_set_text (ssm
->label
, _("Loading..."));
161 Widget
*lw
= WIDGET (ssm
->label
);
163 wd_width
= MAX (wd
->cols
, lw
->cols
+ 6);
164 widget_set_size (wd
, wd
->y
, wd
->x
, wd
->lines
, wd_width
);
165 widget_set_size (lw
, lw
->y
, wd
->x
+ (wd
->cols
- lw
->cols
) / 2, lw
->lines
, lw
->cols
);
169 return status_msg_common_update (sm
);
172 /* --------------------------------------------------------------------------------------------- */
174 * Load file OR text into buffers. Set cursor to the beginning of file.
176 * @return FALSE on error.
180 edit_load_file_fast (edit_buffer_t
* buf
, const vfs_path_t
* filename_vpath
)
184 edit_buffer_read_file_status_msg_t rsm
;
187 file
= mc_open (filename_vpath
, O_RDONLY
| O_BINARY
);
193 g_strdup_printf (_("Cannot open %s for reading"), vfs_path_as_str (filename_vpath
));
194 edit_error_dialog (_("Error"), errmsg
);
203 status_msg_init (STATUS_MSG (&rsm
), _("Load file"), 1.0, simple_status_msg_init_cb
,
204 edit_load_status_update_cb
, NULL
);
206 ret
= (edit_buffer_read_file (buf
, file
, buf
->size
, &rsm
, &aborted
) == buf
->size
);
208 status_msg_deinit (STATUS_MSG (&rsm
));
210 if (!ret
&& !aborted
)
214 errmsg
= g_strdup_printf (_("Error reading %s"), vfs_path_as_str (filename_vpath
));
215 edit_error_dialog (_("Error"), errmsg
);
223 /* --------------------------------------------------------------------------------------------- */
224 /** Return index of the filter or -1 is there is no appropriate filter */
227 edit_find_filter (const vfs_path_t
* filename_vpath
)
231 if (filename_vpath
== NULL
)
234 l
= strlen (vfs_path_as_str (filename_vpath
));
235 for (i
= 0; i
< G_N_ELEMENTS (all_filters
); i
++)
239 e
= strlen (all_filters
[i
].extension
);
241 if (!strcmp (all_filters
[i
].extension
, vfs_path_as_str (filename_vpath
) + l
- e
))
247 /* --------------------------------------------------------------------------------------------- */
250 edit_get_filter (const vfs_path_t
* filename_vpath
)
253 char *p
, *quoted_name
;
255 i
= edit_find_filter (filename_vpath
);
259 quoted_name
= name_quote (vfs_path_as_str (filename_vpath
), FALSE
);
260 p
= g_strdup_printf (all_filters
[i
].read
, quoted_name
);
261 g_free (quoted_name
);
265 /* --------------------------------------------------------------------------------------------- */
268 edit_insert_stream (WEdit
* edit
, FILE * f
)
273 while ((c
= fgetc (f
)) >= 0)
275 edit_insert (edit
, c
);
281 /* --------------------------------------------------------------------------------------------- */
283 * Open file and create it if necessary.
285 * @param edit editor object
286 * @param filename_vpath file name
287 * @param st buffer for store stat info
288 * @return TRUE for success, FALSE for error.
292 check_file_access (WEdit
* edit
, const vfs_path_t
* filename_vpath
, struct stat
*st
)
294 static uintmax_t threshold
= UINTMAX_MAX
;
296 gchar
*errmsg
= NULL
;
299 /* Try opening an existing file */
300 file
= mc_open (filename_vpath
, O_NONBLOCK
| O_RDONLY
| O_BINARY
, 0666);
304 * Try creating the file. O_EXCL prevents following broken links
305 * and opening existing files.
307 file
= mc_open (filename_vpath
, O_NONBLOCK
| O_RDONLY
| O_BINARY
| O_CREAT
| O_EXCL
, 0666);
311 g_strdup_printf (_("Cannot open %s for reading"), vfs_path_as_str (filename_vpath
));
315 /* New file, delete it if it's not modified or saved */
316 edit
->delete_file
= 1;
319 /* Check what we have opened */
320 if (mc_fstat (file
, st
) < 0)
323 g_strdup_printf (_("Cannot get size/permissions for %s"),
324 vfs_path_as_str (filename_vpath
));
328 /* We want to open regular files only */
329 if (!S_ISREG (st
->st_mode
))
332 g_strdup_printf (_("\"%s\" is not a regular file"), vfs_path_as_str (filename_vpath
));
336 /* get file size threshold for alarm */
337 if (threshold
== UINTMAX_MAX
)
339 gboolean err
= FALSE
;
341 threshold
= parse_integer (option_filesize_threshold
, &err
);
343 threshold
= option_filesize_default_threshold
;
347 * Don't delete non-empty files.
348 * O_EXCL should prevent it, but let's be on the safe side.
351 edit
->delete_file
= 0;
353 if ((uintmax_t) st
->st_size
> threshold
)
357 errmsg
= g_strdup_printf (_("File \"%s\" is too large.\nOpen it anyway?"),
358 vfs_path_as_str (filename_vpath
));
359 act
= edit_query_dialog2 (_("Warning"), errmsg
, _("&Yes"), _("&No"));
360 MC_PTR_FREE (errmsg
);
367 (void) mc_close (file
);
371 edit_error_dialog (_("Error"), errmsg
);
379 /* --------------------------------------------------------------------------------------------- */
382 * Open the file and load it into the buffers, either directly or using
383 * a filter. Return TRUE on success, FALSE on error.
385 * Fast loading (edit_load_file_fast) is used when the file size is
386 * known. In this case the data is read into the buffers by blocks.
387 * If the file size is not known, the data is loaded byte by byte in
390 * @param edit editor object
391 * @return TRUE if file was successfully opened and loaded to buffers, FALSE otherwise
394 edit_load_file (WEdit
* edit
)
396 gboolean fast_load
= TRUE
;
398 /* Cannot do fast load if a filter is used */
399 if (edit_find_filter (edit
->filename_vpath
) >= 0)
403 * FIXME: line end translation should disable fast loading as well
404 * Consider doing fseek() to the end and ftell() for the real size.
406 if (edit
->filename_vpath
!= NULL
)
409 * VFS may report file size incorrectly, and slow load is not a big
410 * deal considering overhead in VFS.
412 if (!vfs_file_is_local (edit
->filename_vpath
))
415 /* If we are dealing with a real file, check that it exists */
416 if (!check_file_access (edit
, edit
->filename_vpath
, &edit
->stat1
))
424 /* nothing to load */
430 edit_buffer_init (&edit
->buffer
, edit
->stat1
.st_size
);
432 if (!edit_load_file_fast (&edit
->buffer
, edit
->filename_vpath
))
440 edit_buffer_init (&edit
->buffer
, 0);
442 if (edit
->filename_vpath
!= NULL
443 && *(vfs_path_get_by_index (edit
->filename_vpath
, 0)->path
) != '\0')
445 edit
->undo_stack_disable
= 1;
446 if (edit_insert_file (edit
, edit
->filename_vpath
) < 0)
451 edit
->undo_stack_disable
= 0;
458 /* --------------------------------------------------------------------------------------------- */
460 * Restore saved cursor position and/or bookmarks in the file
462 * @param edit editor object
463 * @param load_position If TRUE, load bookmarks and cursor position and aply them.
464 * If FALSE, load bookmarks only.
468 edit_load_position (WEdit
* edit
, gboolean load_position
)
473 if (edit
->filename_vpath
== NULL
474 || *(vfs_path_get_by_index (edit
->filename_vpath
, 0)->path
) == '\0')
477 load_file_position (edit
->filename_vpath
, &line
, &column
, &offset
, &edit
->serialized_bookmarks
);
478 /* apply bookmarks in any case */
479 book_mark_restore (edit
, BOOK_MARK_COLOR
);
486 edit_move_to_line (edit
, line
- 1);
487 edit
->prev_col
= column
;
491 edit_cursor_move (edit
, offset
);
492 line
= edit
->buffer
.curs_line
;
493 edit
->search_start
= edit
->buffer
.curs1
;
496 edit_move_to_prev_col (edit
, edit_buffer_get_current_bol (&edit
->buffer
));
497 edit_move_display (edit
, line
- (WIDGET (edit
)->lines
/ 2));
500 /* --------------------------------------------------------------------------------------------- */
501 /** Save cursor position in the file */
504 edit_save_position (WEdit
* edit
)
506 if (edit
->filename_vpath
== NULL
507 || *(vfs_path_get_by_index (edit
->filename_vpath
, 0)->path
) == '\0')
510 book_mark_serialize (edit
, BOOK_MARK_COLOR
);
511 save_file_position (edit
->filename_vpath
, edit
->buffer
.curs_line
+ 1, edit
->curs_col
,
512 edit
->buffer
.curs1
, edit
->serialized_bookmarks
);
513 edit
->serialized_bookmarks
= NULL
;
516 /* --------------------------------------------------------------------------------------------- */
517 /** Clean the WEdit stricture except the widget part */
520 edit_purge_widget (WEdit
* edit
)
522 size_t len
= sizeof (WEdit
) - sizeof (Widget
);
523 char *start
= (char *) edit
+ sizeof (Widget
);
524 memset (start
, 0, len
);
527 /* --------------------------------------------------------------------------------------------- */
530 TODO: if the user undos until the stack bottom, and the stack has not wrapped,
531 then the file should be as it was when he loaded up. Then set edit->modified to 0.
535 edit_pop_undo_action (WEdit
* edit
)
538 unsigned long sp
= edit
->undo_stack_pointer
;
540 if (sp
== edit
->undo_stack_bottom
)
543 sp
= (sp
- 1) & edit
->undo_stack_size_mask
;
544 c
= edit
->undo_stack
[sp
];
547 /* edit->undo_stack[sp] = '@'; */
548 edit
->undo_stack_pointer
= (edit
->undo_stack_pointer
- 1) & edit
->undo_stack_size_mask
;
552 if (sp
== edit
->undo_stack_bottom
)
555 c
= edit
->undo_stack
[(sp
- 1) & edit
->undo_stack_size_mask
];
556 if (edit
->undo_stack
[sp
] == -2)
558 /* edit->undo_stack[sp] = '@'; */
559 edit
->undo_stack_pointer
= sp
;
562 edit
->undo_stack
[sp
]++;
568 edit_pop_redo_action (WEdit
* edit
)
571 unsigned long sp
= edit
->redo_stack_pointer
;
573 if (sp
== edit
->redo_stack_bottom
)
576 sp
= (sp
- 1) & edit
->redo_stack_size_mask
;
577 c
= edit
->redo_stack
[sp
];
580 edit
->redo_stack_pointer
= (edit
->redo_stack_pointer
- 1) & edit
->redo_stack_size_mask
;
584 if (sp
== edit
->redo_stack_bottom
)
587 c
= edit
->redo_stack
[(sp
- 1) & edit
->redo_stack_size_mask
];
588 if (edit
->redo_stack
[sp
] == -2)
589 edit
->redo_stack_pointer
= sp
;
591 edit
->redo_stack
[sp
]++;
597 get_prev_undo_action (WEdit
* edit
)
600 unsigned long sp
= edit
->undo_stack_pointer
;
602 if (sp
== edit
->undo_stack_bottom
)
605 sp
= (sp
- 1) & edit
->undo_stack_size_mask
;
606 c
= edit
->undo_stack
[sp
];
610 if (sp
== edit
->undo_stack_bottom
)
613 c
= edit
->undo_stack
[(sp
- 1) & edit
->undo_stack_size_mask
];
617 /* --------------------------------------------------------------------------------------------- */
618 /** is called whenever a modification is made by one of the four routines below */
621 edit_modification (WEdit
* edit
)
623 edit
->caches_valid
= FALSE
;
625 /* raise lock when file modified */
626 if (!edit
->modified
&& !edit
->delete_file
)
627 edit
->locked
= lock_file (edit
->filename_vpath
);
631 /* --------------------------------------------------------------------------------------------- */
632 /* high level cursor movement commands */
633 /* --------------------------------------------------------------------------------------------- */
634 /** check whether cursor is in indent part of line
636 * @param edit editor object
638 * @return TRUE if cursor is in indent, FALSE otherwise
642 is_in_indent (const edit_buffer_t
* buf
)
646 for (p
= edit_buffer_get_current_bol (buf
); p
< buf
->curs1
; p
++)
647 if (strchr (" \t", edit_buffer_get_byte (buf
, p
)) == NULL
)
653 /* --------------------------------------------------------------------------------------------- */
654 /** check whether line in editor is blank or not
656 * @param edit editor object
657 * @param offset position in file
659 * @return TRUE if line in blank, FALSE otherwise
663 is_blank (const edit_buffer_t
* buf
, off_t offset
)
667 s
= edit_buffer_get_bol (buf
, offset
);
668 f
= edit_buffer_get_eol (buf
, offset
) - 1;
673 c
= edit_buffer_get_byte (buf
, s
++);
680 /* --------------------------------------------------------------------------------------------- */
681 /** returns the offset of line i */
684 edit_find_line (WEdit
* edit
, long line
)
687 long m
= 2000000000; /* what is the magic number? */
689 if (!edit
->caches_valid
)
691 memset (edit
->line_numbers
, 0, sizeof (edit
->line_numbers
));
692 memset (edit
->line_offsets
, 0, sizeof (edit
->line_offsets
));
693 /* three offsets that we *know* are line 0 at 0 and these two: */
694 edit
->line_numbers
[1] = edit
->buffer
.curs_line
;
695 edit
->line_offsets
[1] = edit_buffer_get_current_bol (&edit
->buffer
);
696 edit
->line_numbers
[2] = edit
->buffer
.lines
;
697 edit
->line_offsets
[2] = edit_buffer_get_bol (&edit
->buffer
, edit
->buffer
.size
);
698 edit
->caches_valid
= TRUE
;
700 if (line
>= edit
->buffer
.lines
)
701 return edit
->line_offsets
[2];
704 /* find the closest known point */
705 for (i
= 0; i
< N_LINE_CACHES
; i
++)
709 n
= labs (edit
->line_numbers
[i
] - line
);
717 return edit
->line_offsets
[j
]; /* know the offset exactly */
718 if (m
== 1 && j
>= 3)
719 i
= j
; /* one line different - caller might be looping, so stay in this cache */
721 i
= 3 + (rand () % (N_LINE_CACHES
- 3));
722 if (line
> edit
->line_numbers
[j
])
723 edit
->line_offsets
[i
] =
724 edit_buffer_get_forward_offset (&edit
->buffer
, edit
->line_offsets
[j
],
725 line
- edit
->line_numbers
[j
], 0);
727 edit
->line_offsets
[i
] =
728 edit_buffer_get_backward_offset (&edit
->buffer
, edit
->line_offsets
[j
],
729 edit
->line_numbers
[j
] - line
);
730 edit
->line_numbers
[i
] = line
;
731 return edit
->line_offsets
[i
];
734 /* --------------------------------------------------------------------------------------------- */
735 /** moves up until a blank line is reached, or until just
736 before a non-blank line is reached */
739 edit_move_up_paragraph (WEdit
* edit
, gboolean do_scroll
)
743 if (edit
->buffer
.curs_line
> 1)
745 if (!edit_line_is_blank (edit
, edit
->buffer
.curs_line
))
747 for (i
= edit
->buffer
.curs_line
- 1; i
!= 0; i
--)
748 if (edit_line_is_blank (edit
, i
))
751 else if (edit_line_is_blank (edit
, edit
->buffer
.curs_line
- 1))
753 for (i
= edit
->buffer
.curs_line
- 1; i
!= 0; i
--)
754 if (!edit_line_is_blank (edit
, i
))
762 for (i
= edit
->buffer
.curs_line
- 1; i
!= 0; i
--)
763 if (edit_line_is_blank (edit
, i
))
768 edit_move_up (edit
, edit
->buffer
.curs_line
- i
, do_scroll
);
771 /* --------------------------------------------------------------------------------------------- */
772 /** moves down until a blank line is reached, or until just
773 before a non-blank line is reached */
776 edit_move_down_paragraph (WEdit
* edit
, gboolean do_scroll
)
780 if (edit
->buffer
.curs_line
>= edit
->buffer
.lines
- 1)
781 i
= edit
->buffer
.lines
;
782 else if (!edit_line_is_blank (edit
, edit
->buffer
.curs_line
))
784 for (i
= edit
->buffer
.curs_line
+ 1; i
!= 0; i
++)
785 if (edit_line_is_blank (edit
, i
) || i
>= edit
->buffer
.lines
)
788 else if (edit_line_is_blank (edit
, edit
->buffer
.curs_line
+ 1))
790 for (i
= edit
->buffer
.curs_line
+ 1; i
!= 0; i
++)
791 if (!edit_line_is_blank (edit
, i
) || i
> edit
->buffer
.lines
)
799 for (i
= edit
->buffer
.curs_line
+ 1; i
!= 0; i
++)
800 if (edit_line_is_blank (edit
, i
) || i
>= edit
->buffer
.lines
)
803 edit_move_down (edit
, i
- edit
->buffer
.curs_line
, do_scroll
);
806 /* --------------------------------------------------------------------------------------------- */
809 edit_begin_page (WEdit
* edit
)
811 edit_update_curs_row (edit
);
812 edit_move_up (edit
, edit
->curs_row
, FALSE
);
815 /* --------------------------------------------------------------------------------------------- */
818 edit_end_page (WEdit
* edit
)
820 edit_update_curs_row (edit
);
821 edit_move_down (edit
, WIDGET (edit
)->lines
- edit
->curs_row
- 1, FALSE
);
825 /* --------------------------------------------------------------------------------------------- */
826 /** goto beginning of text */
829 edit_move_to_top (WEdit
* edit
)
831 if (edit
->buffer
.curs_line
!= 0)
833 edit_cursor_move (edit
, -edit
->buffer
.curs1
);
834 edit_move_to_prev_col (edit
, 0);
835 edit
->force
|= REDRAW_PAGE
;
836 edit
->search_start
= 0;
837 edit_update_curs_row (edit
);
841 /* --------------------------------------------------------------------------------------------- */
842 /** goto end of text */
845 edit_move_to_bottom (WEdit
* edit
)
847 if (edit
->buffer
.curs_line
< edit
->buffer
.lines
)
849 edit_move_down (edit
, edit
->buffer
.lines
- edit
->curs_row
, FALSE
);
850 edit
->start_display
= edit
->buffer
.size
;
851 edit
->start_line
= edit
->buffer
.lines
;
852 edit_scroll_upward (edit
, WIDGET (edit
)->lines
- 1);
853 edit
->force
|= REDRAW_PAGE
;
857 /* --------------------------------------------------------------------------------------------- */
858 /** goto beginning of line */
861 edit_cursor_to_bol (WEdit
* edit
)
863 edit_cursor_move (edit
, edit_buffer_get_current_bol (&edit
->buffer
) - edit
->buffer
.curs1
);
864 edit
->search_start
= edit
->buffer
.curs1
;
865 edit
->prev_col
= edit_get_col (edit
);
869 /* --------------------------------------------------------------------------------------------- */
870 /** goto end of line */
873 edit_cursor_to_eol (WEdit
* edit
)
875 edit_cursor_move (edit
, edit_buffer_get_current_eol (&edit
->buffer
) - edit
->buffer
.curs1
);
876 edit
->search_start
= edit
->buffer
.curs1
;
877 edit
->prev_col
= edit_get_col (edit
);
881 /* --------------------------------------------------------------------------------------------- */
886 unsigned long x
, r
= 0;
888 const char option_chars_move_whole_word
[] =
889 "!=&|<>^~ !:;, !'!`!.?!\"!( !) !{ !} !Aa0 !+-*/= |<> ![ !] !\\#! ";
896 if (g_ascii_isupper ((gchar
) c
))
898 else if (g_ascii_islower ((gchar
) c
))
900 else if (g_ascii_isalpha (c
))
902 else if (isdigit (c
))
904 else if (isspace (c
))
906 q
= strchr (option_chars_move_whole_word
, c
);
911 for (x
= 1, p
= option_chars_move_whole_word
; p
< q
; p
++)
916 while ((q
= strchr (q
+ 1, c
)));
920 /* --------------------------------------------------------------------------------------------- */
923 edit_left_word_move (WEdit
* edit
, int s
)
929 if (edit
->column_highlight
930 && edit
->mark1
!= edit
->mark2
931 && edit
->over_col
== 0
932 && edit
->buffer
.curs1
== edit_buffer_get_current_bol (&edit
->buffer
))
934 edit_cursor_move (edit
, -1);
935 if (edit
->buffer
.curs1
== 0)
937 c1
= edit_buffer_get_previous_byte (&edit
->buffer
);
938 c2
= edit_buffer_get_current_byte (&edit
->buffer
);
939 if (c1
== '\n' || c2
== '\n')
941 if ((my_type_of (c1
) & my_type_of (c2
)) == 0)
943 if (isspace (c1
) && !isspace (c2
))
945 if (s
!= 0 && !isspace (c1
) && isspace (c2
))
950 /* --------------------------------------------------------------------------------------------- */
953 edit_left_word_move_cmd (WEdit
* edit
)
955 edit_left_word_move (edit
, 0);
956 edit
->force
|= REDRAW_PAGE
;
959 /* --------------------------------------------------------------------------------------------- */
962 edit_right_word_move (WEdit
* edit
, int s
)
968 if (edit
->column_highlight
969 && edit
->mark1
!= edit
->mark2
970 && edit
->over_col
== 0
971 && edit
->buffer
.curs1
== edit_buffer_get_current_eol (&edit
->buffer
))
973 edit_cursor_move (edit
, 1);
974 if (edit
->buffer
.curs1
>= edit
->buffer
.size
)
976 c1
= edit_buffer_get_previous_byte (&edit
->buffer
);
977 c2
= edit_buffer_get_current_byte (&edit
->buffer
);
978 if (c1
== '\n' || c2
== '\n')
980 if ((my_type_of (c1
) & my_type_of (c2
)) == 0)
982 if (isspace (c1
) && !isspace (c2
))
984 if (s
!= 0 && !isspace (c1
) && isspace (c2
))
989 /* --------------------------------------------------------------------------------------------- */
992 edit_right_word_move_cmd (WEdit
* edit
)
994 edit_right_word_move (edit
, 0);
995 edit
->force
|= REDRAW_PAGE
;
998 /* --------------------------------------------------------------------------------------------- */
1001 edit_right_char_move_cmd (WEdit
* edit
)
1003 int char_length
= 1;
1009 c
= edit_buffer_get_utf (&edit
->buffer
, edit
->buffer
.curs1
, &char_length
);
1010 if (char_length
< 1)
1015 c
= edit_buffer_get_current_byte (&edit
->buffer
);
1017 if (option_cursor_beyond_eol
&& c
== '\n')
1020 edit_cursor_move (edit
, char_length
);
1023 /* --------------------------------------------------------------------------------------------- */
1026 edit_left_char_move_cmd (WEdit
* edit
)
1028 int char_length
= 1;
1030 if (edit
->column_highlight
1031 && option_cursor_beyond_eol
1032 && edit
->mark1
!= edit
->mark2
1033 && edit
->over_col
== 0 && edit
->buffer
.curs1
== edit_buffer_get_current_bol (&edit
->buffer
))
1038 edit_buffer_get_prev_utf (&edit
->buffer
, edit
->buffer
.curs1
, &char_length
);
1039 if (char_length
< 1)
1044 if (option_cursor_beyond_eol
&& edit
->over_col
> 0)
1047 edit_cursor_move (edit
, -char_length
);
1050 /* --------------------------------------------------------------------------------------------- */
1051 /** Up or down cursor moving.
1052 direction = TRUE - move up
1057 edit_move_updown (WEdit
* edit
, long lines
, gboolean do_scroll
, gboolean direction
)
1060 long l
= direction
? edit
->buffer
.curs_line
: edit
->buffer
.lines
- edit
->buffer
.curs_line
;
1069 edit
->force
|= REDRAW_PAGE
;
1073 edit_scroll_upward (edit
, lines
);
1075 edit_scroll_downward (edit
, lines
);
1077 p
= edit_buffer_get_current_bol (&edit
->buffer
);
1078 p
= direction
? edit_buffer_get_backward_offset (&edit
->buffer
, p
, lines
) :
1079 edit_buffer_get_forward_offset (&edit
->buffer
, p
, lines
, 0);
1080 edit_cursor_move (edit
, p
- edit
->buffer
.curs1
);
1081 edit_move_to_prev_col (edit
, p
);
1084 /* search start of current multibyte char (like CJK) */
1085 if (edit
->buffer
.curs1
> 0 && edit
->buffer
.curs1
+ 1 < edit
->buffer
.size
1086 && edit_buffer_get_current_byte (&edit
->buffer
) >= 256)
1088 edit_right_char_move_cmd (edit
);
1089 edit_left_char_move_cmd (edit
);
1093 edit
->search_start
= edit
->buffer
.curs1
;
1094 edit
->found_len
= 0;
1097 /* --------------------------------------------------------------------------------------------- */
1100 edit_right_delete_word (WEdit
* edit
)
1102 while (edit
->buffer
.curs1
< edit
->buffer
.size
)
1106 c1
= edit_delete (edit
, TRUE
);
1107 c2
= edit_buffer_get_current_byte (&edit
->buffer
);
1108 if (c1
== '\n' || c2
== '\n')
1110 if ((isspace (c1
) == 0) != (isspace (c2
) == 0))
1112 if ((my_type_of (c1
) & my_type_of (c2
)) == 0)
1117 /* --------------------------------------------------------------------------------------------- */
1120 edit_left_delete_word (WEdit
* edit
)
1122 while (edit
->buffer
.curs1
> 0)
1126 c1
= edit_backspace (edit
, TRUE
);
1127 c2
= edit_buffer_get_previous_byte (&edit
->buffer
);
1128 if (c1
== '\n' || c2
== '\n')
1130 if ((isspace (c1
) == 0) != (isspace (c2
) == 0))
1132 if ((my_type_of (c1
) & my_type_of (c2
)) == 0)
1137 /* --------------------------------------------------------------------------------------------- */
1139 the start column position is not recorded, and hence does not
1140 undo as it happed. But who would notice.
1144 edit_do_undo (WEdit
* edit
)
1149 edit
->undo_stack_disable
= 1; /* don't record undo's onto undo stack! */
1151 while ((ac
= edit_pop_undo_action (edit
)) < KEY_PRESS
)
1158 edit_cursor_move (edit
, 1);
1161 edit_cursor_move (edit
, -1);
1165 edit_backspace (edit
, TRUE
);
1169 edit_delete (edit
, TRUE
);
1172 edit
->column_highlight
= 1;
1175 edit
->column_highlight
= 0;
1180 if (ac
>= 256 && ac
< 512)
1181 edit_insert_ahead (edit
, ac
- 256);
1182 if (ac
>= 0 && ac
< 256)
1183 edit_insert (edit
, ac
);
1185 if (ac
>= MARK_1
- 2 && ac
< MARK_2
- 2)
1187 edit
->mark1
= ac
- MARK_1
;
1189 (long) edit_move_forward3 (edit
, edit_buffer_get_bol (&edit
->buffer
, edit
->mark1
),
1192 if (ac
>= MARK_2
- 2 && ac
< MARK_CURS
- 2)
1194 edit
->mark2
= ac
- MARK_2
;
1196 (long) edit_move_forward3 (edit
, edit_buffer_get_bol (&edit
->buffer
, edit
->mark2
),
1199 else if (ac
>= MARK_CURS
- 2 && ac
< KEY_PRESS
)
1201 edit
->end_mark_curs
= ac
- MARK_CURS
;
1204 edit
->force
|= REDRAW_PAGE
; /* more than one pop usually means something big */
1207 if (edit
->start_display
> ac
- KEY_PRESS
)
1210 edit_buffer_count_lines (&edit
->buffer
, ac
- KEY_PRESS
, edit
->start_display
);
1211 edit
->force
|= REDRAW_PAGE
;
1213 else if (edit
->start_display
< ac
- KEY_PRESS
)
1216 edit_buffer_count_lines (&edit
->buffer
, edit
->start_display
, ac
- KEY_PRESS
);
1217 edit
->force
|= REDRAW_PAGE
;
1219 edit
->start_display
= ac
- KEY_PRESS
; /* see push and pop above */
1220 edit_update_curs_row (edit
);
1223 edit
->undo_stack_disable
= 0;
1226 /* --------------------------------------------------------------------------------------------- */
1229 edit_do_redo (WEdit
* edit
)
1234 if (edit
->redo_stack_reset
)
1238 while ((ac
= edit_pop_redo_action (edit
)) < KEY_PRESS
)
1245 edit_cursor_move (edit
, 1);
1248 edit_cursor_move (edit
, -1);
1251 edit_backspace (edit
, TRUE
);
1254 edit_delete (edit
, TRUE
);
1257 edit
->column_highlight
= 1;
1260 edit
->column_highlight
= 0;
1265 if (ac
>= 256 && ac
< 512)
1266 edit_insert_ahead (edit
, ac
- 256);
1267 if (ac
>= 0 && ac
< 256)
1268 edit_insert (edit
, ac
);
1270 if (ac
>= MARK_1
- 2 && ac
< MARK_2
- 2)
1272 edit
->mark1
= ac
- MARK_1
;
1274 (long) edit_move_forward3 (edit
, edit_buffer_get_bol (&edit
->buffer
, edit
->mark1
),
1277 else if (ac
>= MARK_2
- 2 && ac
< KEY_PRESS
)
1279 edit
->mark2
= ac
- MARK_2
;
1281 (long) edit_move_forward3 (edit
, edit_buffer_get_bol (&edit
->buffer
, edit
->mark2
),
1284 /* more than one pop usually means something big */
1286 edit
->force
|= REDRAW_PAGE
;
1289 if (edit
->start_display
> ac
- KEY_PRESS
)
1292 edit_buffer_count_lines (&edit
->buffer
, ac
- KEY_PRESS
, edit
->start_display
);
1293 edit
->force
|= REDRAW_PAGE
;
1295 else if (edit
->start_display
< ac
- KEY_PRESS
)
1298 edit_buffer_count_lines (&edit
->buffer
, edit
->start_display
, ac
- KEY_PRESS
);
1299 edit
->force
|= REDRAW_PAGE
;
1301 edit
->start_display
= ac
- KEY_PRESS
; /* see push and pop above */
1302 edit_update_curs_row (edit
);
1308 /* --------------------------------------------------------------------------------------------- */
1311 edit_group_undo (WEdit
* edit
)
1313 long ac
= KEY_PRESS
;
1314 long cur_ac
= KEY_PRESS
;
1315 while (ac
!= STACK_BOTTOM
&& ac
== cur_ac
)
1317 cur_ac
= get_prev_undo_action (edit
);
1318 edit_do_undo (edit
);
1319 ac
= get_prev_undo_action (edit
);
1320 /* exit from cycle if option_group_undo is not set,
1321 * and make single UNDO operation
1323 if (!option_group_undo
)
1328 /* --------------------------------------------------------------------------------------------- */
1331 edit_delete_to_line_end (WEdit
* edit
)
1333 while (edit_buffer_get_current_byte (&edit
->buffer
) != '\n' && edit
->buffer
.curs2
!= 0)
1334 edit_delete (edit
, TRUE
);
1337 /* --------------------------------------------------------------------------------------------- */
1340 edit_delete_to_line_begin (WEdit
* edit
)
1342 while (edit_buffer_get_previous_byte (&edit
->buffer
) != '\n' && edit
->buffer
.curs1
!= 0)
1343 edit_backspace (edit
, TRUE
);
1346 /* --------------------------------------------------------------------------------------------- */
1349 is_aligned_on_a_tab (WEdit
* edit
)
1353 edit_update_curs_col (edit
);
1354 curs_col
= edit
->curs_col
% (TAB_SIZE
* space_width
);
1355 return (curs_col
== 0 || curs_col
== (HALF_TAB_SIZE
* space_width
));
1358 /* --------------------------------------------------------------------------------------------- */
1361 right_of_four_spaces (WEdit
* edit
)
1365 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1366 ch
|= edit_buffer_get_byte (&edit
->buffer
, edit
->buffer
.curs1
- i
);
1368 return (ch
== ' ' && is_aligned_on_a_tab (edit
));
1371 /* --------------------------------------------------------------------------------------------- */
1374 left_of_four_spaces (WEdit
* edit
)
1378 for (i
= 0; i
< HALF_TAB_SIZE
; i
++)
1379 ch
|= edit_buffer_get_byte (&edit
->buffer
, edit
->buffer
.curs1
+ i
);
1381 return (ch
== ' ' && is_aligned_on_a_tab (edit
));
1384 /* --------------------------------------------------------------------------------------------- */
1387 edit_auto_indent (WEdit
* edit
)
1391 p
= edit
->buffer
.curs1
;
1392 /* use the previous line as a template */
1393 p
= edit_buffer_get_backward_offset (&edit
->buffer
, p
, 1);
1394 /* copy the leading whitespace of the line */
1396 { /* no range check - the line _is_ \n-terminated */
1399 c
= edit_buffer_get_byte (&edit
->buffer
, p
++);
1400 if (!whitespace (c
))
1402 edit_insert (edit
, c
);
1406 /* --------------------------------------------------------------------------------------------- */
1409 edit_double_newline (WEdit
* edit
)
1411 edit_insert (edit
, '\n');
1412 if (edit_buffer_get_current_byte (&edit
->buffer
) == '\n'
1413 || edit_buffer_get_byte (&edit
->buffer
, edit
->buffer
.curs1
- 2) == '\n')
1415 edit
->force
|= REDRAW_PAGE
;
1416 edit_insert (edit
, '\n');
1419 /* --------------------------------------------------------------------------------------------- */
1422 insert_spaces_tab (WEdit
* edit
, gboolean half
)
1426 edit_update_curs_col (edit
);
1427 i
= option_tab_spacing
* space_width
;
1432 i
= ((edit
->curs_col
/ i
) + 1) * i
- edit
->curs_col
;
1435 edit_insert (edit
, ' ');
1441 /* --------------------------------------------------------------------------------------------- */
1444 edit_tab_cmd (WEdit
* edit
)
1446 if (option_fake_half_tabs
&& is_in_indent (&edit
->buffer
))
1448 /* insert a half tab (usually four spaces) unless there is a
1449 half tab already behind, then delete it and insert a
1451 if (option_fill_tabs_with_spaces
|| !right_of_four_spaces (edit
))
1452 insert_spaces_tab (edit
, TRUE
);
1457 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
1458 edit_backspace (edit
, TRUE
);
1459 edit_insert (edit
, '\t');
1462 else if (option_fill_tabs_with_spaces
)
1463 insert_spaces_tab (edit
, FALSE
);
1465 edit_insert (edit
, '\t');
1468 /* --------------------------------------------------------------------------------------------- */
1471 check_and_wrap_line (WEdit
* edit
)
1475 if (!option_typewriter_wrap
)
1477 edit_update_curs_col (edit
);
1478 if (edit
->curs_col
< option_word_wrap_line_length
)
1480 curs
= edit
->buffer
.curs1
;
1486 c
= edit_buffer_get_byte (&edit
->buffer
, curs
);
1487 if (c
== '\n' || curs
<= 0)
1489 edit_insert (edit
, '\n');
1494 off_t current
= edit
->buffer
.curs1
;
1495 edit_cursor_move (edit
, curs
- edit
->buffer
.curs1
+ 1);
1496 edit_insert (edit
, '\n');
1497 edit_cursor_move (edit
, current
- edit
->buffer
.curs1
+ 1);
1503 /* --------------------------------------------------------------------------------------------- */
1504 /** this find the matching bracket in either direction, and sets edit->bracket
1506 * @param edit editor object
1507 * @param in_screen seach only on the current screen
1508 * @param furthest_bracket_search count of the bytes for search
1510 * @return position of the found bracket (-1 if no match)
1514 edit_get_bracket (WEdit
* edit
, gboolean in_screen
, unsigned long furthest_bracket_search
)
1516 const char *const b
= "{}{[][()(", *p
;
1517 int i
= 1, inc
= -1, c
, d
, n
= 0;
1518 unsigned long j
= 0;
1521 edit_update_curs_row (edit
);
1522 c
= edit_buffer_get_current_byte (&edit
->buffer
);
1524 /* not on a bracket at all */
1525 if (p
== NULL
|| *p
== '\0')
1527 /* the matching bracket */
1529 /* going left or right? */
1530 if (strchr ("{[(", c
) != NULL
)
1533 if (furthest_bracket_search
== 0)
1534 furthest_bracket_search
--; /* ULONG_MAX */
1535 for (q
= edit
->buffer
.curs1
+ inc
;; q
+= inc
)
1539 /* out of buffer? */
1540 if (q
>= edit
->buffer
.size
|| q
< 0)
1542 a
= edit_buffer_get_byte (&edit
->buffer
, q
);
1543 /* don't want to eat CPU */
1544 if (j
++ > furthest_bracket_search
)
1546 /* out of screen? */
1549 if (q
< edit
->start_display
)
1551 /* count lines if searching downward */
1552 if (inc
> 0 && a
== '\n')
1553 if (n
++ >= WIDGET (edit
)->lines
- edit
->curs_row
) /* out of screen */
1556 /* count bracket depth */
1557 i
+= (a
== c
) - (a
== d
);
1558 /* return if bracket depth is zero */
1566 /* --------------------------------------------------------------------------------------------- */
1569 edit_goto_matching_bracket (WEdit
* edit
)
1573 q
= edit_get_bracket (edit
, 0, 0);
1576 edit
->bracket
= edit
->buffer
.curs1
;
1577 edit
->force
|= REDRAW_PAGE
;
1578 edit_cursor_move (edit
, q
- edit
->buffer
.curs1
);
1582 /* --------------------------------------------------------------------------------------------- */
1585 edit_move_block_to_right (WEdit
* edit
)
1587 off_t start_mark
, end_mark
;
1588 long cur_bol
, start_bol
;
1590 if (!eval_marks (edit
, &start_mark
, &end_mark
))
1593 start_bol
= edit_buffer_get_bol (&edit
->buffer
, start_mark
);
1594 cur_bol
= edit_buffer_get_bol (&edit
->buffer
, end_mark
- 1);
1598 edit_cursor_move (edit
, cur_bol
- edit
->buffer
.curs1
);
1599 if (!edit_line_is_blank (edit
, edit
->buffer
.curs_line
))
1601 if (option_fill_tabs_with_spaces
)
1602 insert_spaces_tab (edit
, option_fake_half_tabs
);
1604 edit_insert (edit
, '\t');
1605 edit_cursor_move (edit
,
1606 edit_buffer_get_bol (&edit
->buffer
, cur_bol
) - edit
->buffer
.curs1
);
1612 cur_bol
= edit_buffer_get_bol (&edit
->buffer
, cur_bol
- 1);
1614 while (cur_bol
>= start_bol
);
1616 edit
->force
|= REDRAW_PAGE
;
1619 /* --------------------------------------------------------------------------------------------- */
1622 edit_move_block_to_left (WEdit
* edit
)
1624 off_t start_mark
, end_mark
;
1625 off_t cur_bol
, start_bol
;
1627 if (!eval_marks (edit
, &start_mark
, &end_mark
))
1630 start_bol
= edit_buffer_get_bol (&edit
->buffer
, start_mark
);
1631 cur_bol
= edit_buffer_get_bol (&edit
->buffer
, end_mark
- 1);
1638 edit_cursor_move (edit
, cur_bol
- edit
->buffer
.curs1
);
1640 if (option_fake_half_tabs
)
1641 del_tab_width
= HALF_TAB_SIZE
;
1643 del_tab_width
= option_tab_spacing
;
1645 next_char
= edit_buffer_get_current_byte (&edit
->buffer
);
1646 if (next_char
== '\t')
1647 edit_delete (edit
, TRUE
);
1648 else if (next_char
== ' ')
1652 for (i
= 0; i
< del_tab_width
; i
++)
1654 if (next_char
== ' ')
1655 edit_delete (edit
, TRUE
);
1656 next_char
= edit_buffer_get_current_byte (&edit
->buffer
);
1663 cur_bol
= edit_buffer_get_bol (&edit
->buffer
, cur_bol
- 1);
1665 while (cur_bol
>= start_bol
);
1667 edit
->force
|= REDRAW_PAGE
;
1670 /* --------------------------------------------------------------------------------------------- */
1672 * prints at the cursor
1673 * @return number of chars printed
1677 edit_print_string (WEdit
* e
, const char *s
)
1681 while (s
[i
] != '\0')
1682 edit_execute_cmd (e
, CK_InsertChar
, (unsigned char) s
[i
++]);
1683 e
->force
|= REDRAW_COMPLETELY
;
1684 edit_update_screen (e
);
1688 /* --------------------------------------------------------------------------------------------- */
1691 edit_insert_column_from_file (WEdit
* edit
, int file
, off_t
* start_pos
, off_t
* end_pos
,
1692 long *col1
, long *col2
)
1696 off_t blocklen
= -1, width
= 0;
1697 unsigned char *data
;
1699 cursor
= edit
->buffer
.curs1
;
1700 col
= edit_get_col (edit
);
1701 data
= g_malloc0 (TEMP_BUF_LEN
);
1703 while ((blocklen
= mc_read (file
, (char *) data
, TEMP_BUF_LEN
)) > 0)
1708 pn
= strchr ((char *) data
, '\n');
1709 width
= pn
== NULL
? blocklen
: pn
- (char *) data
;
1711 for (i
= 0; i
< blocklen
; i
++)
1713 if (data
[i
] != '\n')
1714 edit_insert (edit
, data
[i
]);
1716 { /* fill in and move to next line */
1720 if (edit_buffer_get_current_byte (&edit
->buffer
) != '\n')
1721 for (l
= width
- (edit_get_col (edit
) - col
); l
> 0; l
-= space_width
)
1722 edit_insert (edit
, ' ');
1724 for (p
= edit
->buffer
.curs1
;; p
++)
1726 if (p
== edit
->buffer
.size
)
1728 edit_cursor_move (edit
, edit
->buffer
.size
- edit
->buffer
.curs1
);
1729 edit_insert_ahead (edit
, '\n');
1733 if (edit_buffer_get_byte (&edit
->buffer
, p
) == '\n')
1740 edit_cursor_move (edit
, edit_move_forward3 (edit
, p
, col
, 0) - edit
->buffer
.curs1
);
1742 for (l
= col
- edit_get_col (edit
); l
>= space_width
; l
-= space_width
)
1743 edit_insert (edit
, ' ');
1748 *col2
= col
+ width
;
1749 *start_pos
= cursor
;
1750 *end_pos
= edit
->buffer
.curs1
;
1751 edit_cursor_move (edit
, cursor
- edit
->buffer
.curs1
);
1757 /* --------------------------------------------------------------------------------------------- */
1758 /*** public functions ****************************************************************************/
1759 /* --------------------------------------------------------------------------------------------- */
1761 /** User edit menu, like user menu (F2) but only in editor. */
1764 user_menu (WEdit
* edit
, const char *menu_file
, int selected_entry
)
1769 off_t start_mark
, end_mark
;
1771 vfs_path_t
*block_file_vpath
;
1773 block_file
= mc_config_get_full_path (EDIT_BLOCK_FILE
);
1774 block_file_vpath
= vfs_path_from_str (block_file
);
1775 curs
= edit
->buffer
.curs1
;
1776 nomark
= !eval_marks (edit
, &start_mark
, &end_mark
);
1778 edit_save_block (edit
, block_file
, start_mark
, end_mark
);
1780 /* run shell scripts from menu */
1781 if (user_menu_cmd (edit
, menu_file
, selected_entry
)
1782 && (mc_stat (block_file_vpath
, &status
) == 0) && (status
.st_size
!= 0))
1787 /* i.e. we have marked block */
1789 rc
= edit_block_delete_cmd (edit
);
1795 ins_len
= edit_insert_file (edit
, block_file_vpath
);
1796 if (!nomark
&& ins_len
> 0)
1797 edit_set_markers (edit
, start_mark
, start_mark
+ ins_len
, 0, 0);
1799 /* truncate block file */
1800 fd
= fopen (block_file
, "w");
1804 g_free (block_file
);
1805 vfs_path_free (block_file_vpath
);
1807 edit_cursor_move (edit
, curs
- edit
->buffer
.curs1
);
1808 edit
->force
|= REDRAW_PAGE
;
1809 widget_redraw (WIDGET (edit
));
1812 /* --------------------------------------------------------------------------------------------- */
1815 edit_get_write_filter (const vfs_path_t
* write_name_vpath
, const vfs_path_t
* filename_vpath
)
1818 char *p
, *writename
;
1819 const vfs_path_element_t
*path_element
;
1821 i
= edit_find_filter (filename_vpath
);
1825 path_element
= vfs_path_get_by_index (write_name_vpath
, -1);
1826 writename
= name_quote (path_element
->path
, FALSE
);
1827 p
= g_strdup_printf (all_filters
[i
].write
, writename
);
1832 /* --------------------------------------------------------------------------------------------- */
1834 * @param edit editor object
1835 * @param f value of stream file
1836 * @return the length of the file
1840 edit_write_stream (WEdit
* edit
, FILE * f
)
1844 if (edit
->lb
== LB_ASIS
)
1846 for (i
= 0; i
< edit
->buffer
.size
; i
++)
1847 if (fputc (edit_buffer_get_byte (&edit
->buffer
, i
), f
) < 0)
1852 /* change line breaks */
1853 for (i
= 0; i
< edit
->buffer
.size
; i
++)
1857 c
= edit_buffer_get_byte (&edit
->buffer
, i
);
1858 if (!(c
== '\n' || c
== '\r'))
1860 /* not line break */
1861 if (fputc (c
, f
) < 0)
1865 { /* (c == '\n' || c == '\r') */
1868 c1
= edit_buffer_get_byte (&edit
->buffer
, i
+ 1); /* next char */
1872 case LB_UNIX
: /* replace "\r\n" or '\r' to '\n' */
1873 /* put one line break unconditionally */
1874 if (fputc ('\n', f
) < 0)
1877 i
++; /* 2 chars are processed */
1879 if (c
== '\r' && c1
== '\n')
1880 /* Windows line break; go to the next char */
1883 if (c
== '\r' && c1
== '\r')
1885 /* two Macintosh line breaks; put second line break */
1886 if (fputc ('\n', f
) < 0)
1891 if (fputc (c1
, f
) < 0)
1895 case LB_WIN
: /* replace '\n' or '\r' to "\r\n" */
1896 /* put one line break unconditionally */
1897 if (fputc ('\r', f
) < 0 || fputc ('\n', f
) < 0)
1900 if (c
== '\r' && c1
== '\n')
1901 /* Windows line break; go to the next char */
1905 case LB_MAC
: /* replace "\r\n" or '\n' to '\r' */
1906 /* put one line break unconditionally */
1907 if (fputc ('\r', f
) < 0)
1910 i
++; /* 2 chars are processed */
1912 if (c
== '\r' && c1
== '\n')
1913 /* Windows line break; go to the next char */
1916 if (c
== '\n' && c1
== '\n')
1918 /* two Windows line breaks; put second line break */
1919 if (fputc ('\r', f
) < 0)
1924 if (fputc (c1
, f
) < 0)
1927 case LB_ASIS
: /* default without changes */
1934 return edit
->buffer
.size
;
1937 /* --------------------------------------------------------------------------------------------- */
1940 is_break_char (char c
)
1942 return (isspace (c
) || strchr ("{}[]()<>=|/\\!?~-+`'\",.;:#$%^&*", c
));
1945 /* --------------------------------------------------------------------------------------------- */
1946 /** inserts a file at the cursor, returns count of inserted bytes on success */
1949 edit_insert_file (WEdit
* edit
, const vfs_path_t
* filename_vpath
)
1955 p
= edit_get_filter (filename_vpath
);
1956 current
= edit
->buffer
.curs1
;
1962 f
= (FILE *) popen (p
, "r");
1965 edit_insert_stream (edit
, f
);
1967 /* Place cursor at the end of text selection */
1968 if (!option_cursor_after_inserted_block
)
1970 ins_len
= edit
->buffer
.curs1
- current
;
1971 edit_cursor_move (edit
, -ins_len
);
1977 errmsg
= g_strdup_printf (_("Error reading from pipe: %s"), p
);
1978 edit_error_dialog (_("Error"), errmsg
);
1987 errmsg
= g_strdup_printf (_("Cannot open pipe for reading: %s"), p
);
1988 edit_error_dialog (_("Error"), errmsg
);
1998 int vertical_insertion
= 0;
2001 file
= mc_open (filename_vpath
, O_RDONLY
| O_BINARY
);
2005 buf
= g_malloc0 (TEMP_BUF_LEN
);
2006 blocklen
= mc_read (file
, buf
, sizeof (VERTICAL_MAGIC
));
2009 /* if contain signature VERTICAL_MAGIC then it vertical block */
2010 if (memcmp (buf
, VERTICAL_MAGIC
, sizeof (VERTICAL_MAGIC
)) == 0)
2011 vertical_insertion
= 1;
2013 mc_lseek (file
, 0, SEEK_SET
);
2016 if (vertical_insertion
)
2021 blocklen
= edit_insert_column_from_file (edit
, file
, &mark1
, &mark2
, &c1
, &c2
);
2022 edit_set_markers (edit
, edit
->buffer
.curs1
, mark2
, c1
, c2
);
2024 /* highlight inserted text then not persistent blocks */
2025 if (!option_persistent_selections
&& edit
->modified
)
2027 if (!edit
->column_highlight
)
2028 edit_push_undo_action (edit
, COLUMN_OFF
);
2029 edit
->column_highlight
= 1;
2036 while ((blocklen
= mc_read (file
, (char *) buf
, TEMP_BUF_LEN
)) > 0)
2038 for (i
= 0; i
< blocklen
; i
++)
2039 edit_insert (edit
, buf
[i
]);
2041 /* highlight inserted text then not persistent blocks */
2042 if (!option_persistent_selections
&& edit
->modified
)
2044 edit_set_markers (edit
, edit
->buffer
.curs1
, current
, 0, 0);
2045 if (edit
->column_highlight
)
2046 edit_push_undo_action (edit
, COLUMN_ON
);
2047 edit
->column_highlight
= 0;
2050 /* Place cursor at the end of text selection */
2051 if (!option_cursor_after_inserted_block
)
2053 ins_len
= edit
->buffer
.curs1
- current
;
2054 edit_cursor_move (edit
, -ins_len
);
2058 edit
->force
|= REDRAW_PAGE
;
2068 /* --------------------------------------------------------------------------------------------- */
2070 * Fill in the edit structure. Return NULL on failure. Pass edit as
2071 * NULL to allocate a new structure.
2073 * If line is 0, try to restore saved position. Otherwise put the
2074 * cursor on that line and show it in the middle of the screen.
2078 edit_init (WEdit
* edit
, int y
, int x
, int lines
, int cols
, const vfs_path_t
* filename_vpath
,
2081 gboolean to_free
= FALSE
;
2083 option_auto_syntax
= TRUE
; /* Resetting to auto on every invokation */
2084 option_line_state_width
= option_line_state
? LINE_STATE_WIDTH
: 0;
2088 /* save some widget parameters */
2089 gboolean fullscreen
= edit
->fullscreen
;
2090 int y_prev
= edit
->y_prev
;
2091 int x_prev
= edit
->x_prev
;
2092 int lines_prev
= edit
->lines_prev
;
2093 int cols_prev
= edit
->cols_prev
;
2095 edit_purge_widget (edit
);
2097 /* restore saved parameters */
2098 edit
->fullscreen
= fullscreen
;
2099 edit
->y_prev
= y_prev
;
2100 edit
->x_prev
= x_prev
;
2101 edit
->lines_prev
= lines_prev
;
2102 edit
->cols_prev
= cols_prev
;
2107 edit
= g_malloc0 (sizeof (WEdit
));
2111 widget_init (w
, y
, x
, lines
, cols
, NULL
, NULL
);
2112 w
->options
|= WOP_SELECTABLE
| WOP_TOP_SELECT
| WOP_WANT_CURSOR
;
2113 edit
->fullscreen
= TRUE
;
2114 edit_save_size (edit
);
2117 edit
->drag_state
= MCEDIT_DRAG_NONE
;
2119 edit
->stat1
.st_mode
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
2120 edit
->stat1
.st_uid
= getuid ();
2121 edit
->stat1
.st_gid
= getgid ();
2122 edit
->stat1
.st_mtime
= 0;
2126 edit
->last_bracket
= -1;
2127 edit
->force
|= REDRAW_PAGE
;
2129 /* set file name before load file */
2130 edit_set_filename (edit
, filename_vpath
);
2132 edit
->undo_stack_size
= START_STACK_SIZE
;
2133 edit
->undo_stack_size_mask
= START_STACK_SIZE
- 1;
2134 edit
->undo_stack
= g_malloc0 ((edit
->undo_stack_size
+ 10) * sizeof (long));
2136 edit
->redo_stack_size
= START_STACK_SIZE
;
2137 edit
->redo_stack_size_mask
= START_STACK_SIZE
- 1;
2138 edit
->redo_stack
= g_malloc0 ((edit
->redo_stack_size
+ 10) * sizeof (long));
2142 edit
->converter
= str_cnv_from_term
;
2143 edit_set_codeset (edit
);
2146 if (!edit_load_file (edit
))
2148 /* edit_load_file already gives an error message */
2154 edit
->loading_done
= 1;
2157 edit_load_syntax (edit
, NULL
, NULL
);
2158 edit_get_syntax_color (edit
, -1);
2160 /* load saved cursor position and/or boolmarks */
2161 if ((line
== 0) && option_save_position
)
2162 edit_load_position (edit
, TRUE
);
2165 edit_load_position (edit
, FALSE
);
2168 edit_move_display (edit
, line
- 1);
2169 edit_move_to_line (edit
, line
- 1);
2172 edit_load_macro_cmd (edit
);
2177 /* --------------------------------------------------------------------------------------------- */
2179 /** Clear the edit struct, freeing everything in it. Return TRUE on success */
2181 edit_clean (WEdit
* edit
)
2186 /* a stale lock, remove it */
2188 edit
->locked
= unlock_file (edit
->filename_vpath
);
2190 /* save cursor position */
2191 if (option_save_position
)
2192 edit_save_position (edit
);
2193 else if (edit
->serialized_bookmarks
!= NULL
)
2194 edit
->serialized_bookmarks
= (GArray
*) g_array_free (edit
->serialized_bookmarks
, TRUE
);
2196 /* File specified on the mcedit command line and never saved */
2197 if (edit
->delete_file
)
2198 unlink (vfs_path_get_last_path_str (edit
->filename_vpath
));
2200 edit_free_syntax_rules (edit
);
2201 book_mark_flush (edit
, -1);
2203 edit_buffer_clean (&edit
->buffer
);
2205 g_free (edit
->undo_stack
);
2206 g_free (edit
->redo_stack
);
2207 vfs_path_free (edit
->filename_vpath
);
2208 vfs_path_free (edit
->dir_vpath
);
2209 mc_search_free (edit
->search
);
2210 edit
->search
= NULL
;
2211 MC_PTR_FREE (edit
->last_search_string
);
2214 if (edit
->converter
!= str_cnv_from_term
)
2215 str_close_conv (edit
->converter
);
2218 edit_purge_widget (edit
);
2223 /* --------------------------------------------------------------------------------------------- */
2226 * Load a new file into the editor and set line. If it fails, preserve the old file.
2227 * To do it, allocate a new widget, initialize it and, if the new file
2228 * was loaded, copy the data to the old widget.
2230 * @return TRUE on success, FALSE on failure.
2233 edit_reload_line (WEdit
* edit
, const vfs_path_t
* filename_vpath
, long line
)
2235 Widget
*w
= WIDGET (edit
);
2238 e
= g_malloc0 (sizeof (WEdit
));
2240 /* save some widget parameters */
2241 e
->fullscreen
= edit
->fullscreen
;
2242 e
->y_prev
= edit
->y_prev
;
2243 e
->x_prev
= edit
->x_prev
;
2244 e
->lines_prev
= edit
->lines_prev
;
2245 e
->cols_prev
= edit
->cols_prev
;
2247 if (edit_init (e
, w
->y
, w
->x
, w
->lines
, w
->cols
, filename_vpath
, line
) == NULL
)
2254 memcpy (edit
, e
, sizeof (*edit
));
2260 /* --------------------------------------------------------------------------------------------- */
2264 edit_set_codeset (WEdit
* edit
)
2269 get_codepage_id (mc_global
.source_codepage
>=
2270 0 ? mc_global
.source_codepage
: mc_global
.display_codepage
);
2275 conv
= str_crt_conv_from (cp_id
);
2276 if (conv
!= INVALID_CONV
)
2278 if (edit
->converter
!= str_cnv_from_term
)
2279 str_close_conv (edit
->converter
);
2280 edit
->converter
= conv
;
2285 edit
->utf8
= str_isutf8 (cp_id
);
2289 /* --------------------------------------------------------------------------------------------- */
2292 * Recording stack for undo:
2293 * The following is an implementation of a compressed stack. Identical
2294 * pushes are recorded by a negative prefix indicating the number of times the
2295 * same char was pushed. This saves space for repeated curs-left or curs-right
2312 * If the stack long int is 0-255 it represents a normal insert (from a backspace),
2313 * 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
2314 * of the cursor functions define'd in edit-impl.h. 1000 through 700'000'000 is to
2315 * set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
2318 * The only way the cursor moves or the buffer is changed is through the routines:
2319 * insert, backspace, insert_ahead, delete, and cursor_move.
2320 * These record the reverse undo movements onto the stack each time they are
2323 * Each key press results in a set of actions (insert; delete ...). So each time
2324 * a key is pressed the current position of start_display is pushed as
2325 * KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
2326 * over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
2327 * tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
2331 * @param edit editor object
2332 * @param c code of the action
2336 edit_push_undo_action (WEdit
* edit
, long c
)
2338 unsigned long sp
= edit
->undo_stack_pointer
;
2342 /* first enlarge the stack if necessary */
2343 if (sp
> edit
->undo_stack_size
- 10)
2345 if (option_max_undo
< 256)
2346 option_max_undo
= 256;
2347 if (edit
->undo_stack_size
< (unsigned long) option_max_undo
)
2349 t
= g_realloc (edit
->undo_stack
, (edit
->undo_stack_size
* 2 + 10) * sizeof (long));
2352 edit
->undo_stack
= t
;
2353 edit
->undo_stack_size
<<= 1;
2354 edit
->undo_stack_size_mask
= edit
->undo_stack_size
- 1;
2358 spm1
= (edit
->undo_stack_pointer
- 1) & edit
->undo_stack_size_mask
;
2359 if (edit
->undo_stack_disable
)
2361 edit_push_redo_action (edit
, KEY_PRESS
);
2362 edit_push_redo_action (edit
, c
);
2366 if (edit
->redo_stack_reset
)
2367 edit
->redo_stack_bottom
= edit
->redo_stack_pointer
= 0;
2369 if (edit
->undo_stack_bottom
!= sp
2370 && spm1
!= edit
->undo_stack_bottom
2371 && ((sp
- 2) & edit
->undo_stack_size_mask
) != edit
->undo_stack_bottom
)
2374 if (edit
->undo_stack
[spm1
] < 0)
2376 d
= edit
->undo_stack
[(sp
- 2) & edit
->undo_stack_size_mask
];
2377 if (d
== c
&& edit
->undo_stack
[spm1
] > -1000000000)
2379 if (c
< KEY_PRESS
) /* --> no need to push multiple do-nothings */
2380 edit
->undo_stack
[spm1
]--;
2386 d
= edit
->undo_stack
[spm1
];
2390 return; /* --> no need to push multiple do-nothings */
2391 edit
->undo_stack
[sp
] = -2;
2396 edit
->undo_stack
[sp
] = c
;
2399 edit
->undo_stack_pointer
= (edit
->undo_stack_pointer
+ 1) & edit
->undo_stack_size_mask
;
2401 /* if the sp wraps round and catches the undo_stack_bottom then erase
2402 * the first set of actions on the stack to make space - by moving
2403 * undo_stack_bottom forward one "key press" */
2404 c
= (edit
->undo_stack_pointer
+ 2) & edit
->undo_stack_size_mask
;
2405 if ((unsigned long) c
== edit
->undo_stack_bottom
||
2406 (((unsigned long) c
+ 1) & edit
->undo_stack_size_mask
) == edit
->undo_stack_bottom
)
2409 edit
->undo_stack_bottom
= (edit
->undo_stack_bottom
+ 1) & edit
->undo_stack_size_mask
;
2411 while (edit
->undo_stack
[edit
->undo_stack_bottom
] < KEY_PRESS
2412 && edit
->undo_stack_bottom
!= edit
->undo_stack_pointer
);
2414 /*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: */
2415 if (edit
->undo_stack_pointer
!= edit
->undo_stack_bottom
2416 && edit
->undo_stack
[edit
->undo_stack_bottom
] < KEY_PRESS
)
2418 edit
->undo_stack_bottom
= edit
->undo_stack_pointer
= 0;
2422 /* --------------------------------------------------------------------------------------------- */
2425 edit_push_redo_action (WEdit
* edit
, long c
)
2427 unsigned long sp
= edit
->redo_stack_pointer
;
2430 /* first enlarge the stack if necessary */
2431 if (sp
> edit
->redo_stack_size
- 10)
2433 if (option_max_undo
< 256)
2434 option_max_undo
= 256;
2435 if (edit
->redo_stack_size
< (unsigned long) option_max_undo
)
2437 t
= g_realloc (edit
->redo_stack
, (edit
->redo_stack_size
* 2 + 10) * sizeof (long));
2440 edit
->redo_stack
= t
;
2441 edit
->redo_stack_size
<<= 1;
2442 edit
->redo_stack_size_mask
= edit
->redo_stack_size
- 1;
2446 spm1
= (edit
->redo_stack_pointer
- 1) & edit
->redo_stack_size_mask
;
2448 if (edit
->redo_stack_bottom
!= sp
2449 && spm1
!= edit
->redo_stack_bottom
2450 && ((sp
- 2) & edit
->redo_stack_size_mask
) != edit
->redo_stack_bottom
)
2453 if (edit
->redo_stack
[spm1
] < 0)
2455 d
= edit
->redo_stack
[(sp
- 2) & edit
->redo_stack_size_mask
];
2456 if (d
== c
&& edit
->redo_stack
[spm1
] > -1000000000)
2458 if (c
< KEY_PRESS
) /* --> no need to push multiple do-nothings */
2459 edit
->redo_stack
[spm1
]--;
2465 d
= edit
->redo_stack
[spm1
];
2469 return; /* --> no need to push multiple do-nothings */
2470 edit
->redo_stack
[sp
] = -2;
2471 goto redo_check_bottom
;
2475 edit
->redo_stack
[sp
] = c
;
2478 edit
->redo_stack_pointer
= (edit
->redo_stack_pointer
+ 1) & edit
->redo_stack_size_mask
;
2480 /* if the sp wraps round and catches the redo_stack_bottom then erase
2481 * the first set of actions on the stack to make space - by moving
2482 * redo_stack_bottom forward one "key press" */
2483 c
= (edit
->redo_stack_pointer
+ 2) & edit
->redo_stack_size_mask
;
2484 if ((unsigned long) c
== edit
->redo_stack_bottom
||
2485 (((unsigned long) c
+ 1) & edit
->redo_stack_size_mask
) == edit
->redo_stack_bottom
)
2488 edit
->redo_stack_bottom
= (edit
->redo_stack_bottom
+ 1) & edit
->redo_stack_size_mask
;
2490 while (edit
->redo_stack
[edit
->redo_stack_bottom
] < KEY_PRESS
2491 && edit
->redo_stack_bottom
!= edit
->redo_stack_pointer
);
2494 * If a single key produced enough pushes to wrap all the way round then
2495 * we would notice that the [redo_stack_bottom] does not contain KEY_PRESS.
2496 * The stack is then initialised:
2499 if (edit
->redo_stack_pointer
!= edit
->redo_stack_bottom
2500 && edit
->redo_stack
[edit
->redo_stack_bottom
] < KEY_PRESS
)
2501 edit
->redo_stack_bottom
= edit
->redo_stack_pointer
= 0;
2504 /* --------------------------------------------------------------------------------------------- */
2506 Basic low level single character buffer alterations and movements at the cursor.
2510 edit_insert (WEdit
* edit
, int c
)
2512 /* first we must update the position of the display window */
2513 if (edit
->buffer
.curs1
< edit
->start_display
)
2515 edit
->start_display
++;
2520 /* Mark file as modified, unless the file hasn't been fully loaded */
2521 if (edit
->loading_done
)
2522 edit_modification (edit
);
2524 /* now we must update some info on the file and check if a redraw is required */
2527 book_mark_inc (edit
, edit
->buffer
.curs_line
);
2528 edit
->buffer
.curs_line
++;
2529 edit
->buffer
.lines
++;
2530 edit
->force
|= REDRAW_LINE_ABOVE
| REDRAW_AFTER_CURSOR
;
2533 /* save the reverse command onto the undo stack */
2534 /* ordinary char and not space */
2536 edit_push_undo_action (edit
, BACKSPACE
);
2538 edit_push_undo_action (edit
, BACKSPACE_BR
);
2539 /* update markers */
2540 edit
->mark1
+= (edit
->mark1
> edit
->buffer
.curs1
) ? 1 : 0;
2541 edit
->mark2
+= (edit
->mark2
> edit
->buffer
.curs1
) ? 1 : 0;
2542 edit
->last_get_rule
+= (edit
->last_get_rule
> edit
->buffer
.curs1
) ? 1 : 0;
2544 edit_buffer_insert (&edit
->buffer
, c
);
2547 /* --------------------------------------------------------------------------------------------- */
2548 /** same as edit_insert and move left */
2551 edit_insert_ahead (WEdit
* edit
, int c
)
2553 if (edit
->buffer
.curs1
< edit
->start_display
)
2555 edit
->start_display
++;
2559 edit_modification (edit
);
2562 book_mark_inc (edit
, edit
->buffer
.curs_line
);
2563 edit
->buffer
.lines
++;
2564 edit
->force
|= REDRAW_AFTER_CURSOR
;
2566 /* ordinary char and not space */
2568 edit_push_undo_action (edit
, DELCHAR
);
2570 edit_push_undo_action (edit
, DELCHAR_BR
);
2572 edit
->mark1
+= (edit
->mark1
>= edit
->buffer
.curs1
) ? 1 : 0;
2573 edit
->mark2
+= (edit
->mark2
>= edit
->buffer
.curs1
) ? 1 : 0;
2574 edit
->last_get_rule
+= (edit
->last_get_rule
>= edit
->buffer
.curs1
) ? 1 : 0;
2576 edit_buffer_insert_ahead (&edit
->buffer
, c
);
2579 /* --------------------------------------------------------------------------------------------- */
2582 edit_insert_over (WEdit
* edit
)
2586 for (i
= 0; i
< edit
->over_col
; i
++)
2587 edit_insert (edit
, ' ');
2592 /* --------------------------------------------------------------------------------------------- */
2595 edit_delete (WEdit
* edit
, gboolean byte_delete
)
2598 int char_length
= 1;
2601 if (edit
->buffer
.curs2
== 0)
2605 /* if byte_delete == TRUE then delete only one byte not multibyte char */
2606 if (edit
->utf8
&& !byte_delete
)
2608 edit_buffer_get_utf (&edit
->buffer
, edit
->buffer
.curs1
, &char_length
);
2609 if (char_length
< 1)
2616 if (edit
->mark2
!= edit
->mark1
)
2617 edit_push_markers (edit
);
2619 for (i
= 1; i
<= char_length
; i
++)
2621 if (edit
->mark1
> edit
->buffer
.curs1
)
2624 edit
->end_mark_curs
--;
2626 if (edit
->mark2
> edit
->buffer
.curs1
)
2628 if (edit
->last_get_rule
> edit
->buffer
.curs1
)
2629 edit
->last_get_rule
--;
2631 p
= edit_buffer_delete (&edit
->buffer
);
2633 edit_push_undo_action (edit
, p
+ 256);
2636 edit_modification (edit
);
2639 book_mark_dec (edit
, edit
->buffer
.curs_line
);
2640 edit
->buffer
.lines
--;
2641 edit
->force
|= REDRAW_AFTER_CURSOR
;
2643 if (edit
->buffer
.curs1
< edit
->start_display
)
2645 edit
->start_display
--;
2653 /* --------------------------------------------------------------------------------------------- */
2656 edit_backspace (WEdit
* edit
, gboolean byte_delete
)
2659 int char_length
= 1;
2662 if (edit
->buffer
.curs1
== 0)
2665 if (edit
->mark2
!= edit
->mark1
)
2666 edit_push_markers (edit
);
2669 if (edit
->utf8
&& !byte_delete
)
2671 edit_buffer_get_prev_utf (&edit
->buffer
, edit
->buffer
.curs1
, &char_length
);
2672 if (char_length
< 1)
2679 for (i
= 1; i
<= char_length
; i
++)
2681 if (edit
->mark1
>= edit
->buffer
.curs1
)
2684 edit
->end_mark_curs
--;
2686 if (edit
->mark2
>= edit
->buffer
.curs1
)
2688 if (edit
->last_get_rule
>= edit
->buffer
.curs1
)
2689 edit
->last_get_rule
--;
2691 p
= edit_buffer_backspace (&edit
->buffer
);
2693 edit_push_undo_action (edit
, p
);
2695 edit_modification (edit
);
2698 book_mark_dec (edit
, edit
->buffer
.curs_line
);
2699 edit
->buffer
.curs_line
--;
2700 edit
->buffer
.lines
--;
2701 edit
->force
|= REDRAW_AFTER_CURSOR
;
2704 if (edit
->buffer
.curs1
< edit
->start_display
)
2706 edit
->start_display
--;
2714 /* --------------------------------------------------------------------------------------------- */
2715 /** moves the cursor right or left: increment positive or negative respectively */
2718 edit_cursor_move (WEdit
* edit
, off_t increment
)
2722 for (; increment
< 0 && edit
->buffer
.curs1
!= 0; increment
++)
2726 edit_push_undo_action (edit
, CURS_RIGHT
);
2728 c
= edit_buffer_get_previous_byte (&edit
->buffer
);
2729 edit_buffer_insert_ahead (&edit
->buffer
, c
);
2730 c
= edit_buffer_backspace (&edit
->buffer
);
2733 edit
->buffer
.curs_line
--;
2734 edit
->force
|= REDRAW_LINE_BELOW
;
2740 for (; increment
> 0 && edit
->buffer
.curs2
!= 0; increment
--)
2744 edit_push_undo_action (edit
, CURS_LEFT
);
2746 c
= edit_buffer_get_current_byte (&edit
->buffer
);
2747 edit_buffer_insert (&edit
->buffer
, c
);
2748 c
= edit_buffer_delete (&edit
->buffer
);
2751 edit
->buffer
.curs_line
++;
2752 edit
->force
|= REDRAW_LINE_ABOVE
;
2758 /* --------------------------------------------------------------------------------------------- */
2759 /* If cols is zero this returns the count of columns from current to upto. */
2760 /* If upto is zero returns index of cols across from current. */
2763 edit_move_forward3 (const WEdit
* edit
, off_t current
, long cols
, off_t upto
)
2774 q
= edit
->buffer
.size
+ 2;
2776 for (col
= 0, p
= current
; p
< q
; p
++)
2788 orig_c
= c
= edit_buffer_get_byte (&edit
->buffer
, p
);
2794 int char_length
= 1;
2796 utf_ch
= edit_buffer_get_utf (&edit
->buffer
, p
, &char_length
);
2797 if (mc_global
.utf8_display
)
2799 if (char_length
> 1)
2800 col
-= char_length
- 1;
2801 if (g_unichar_iswide (utf_ch
))
2804 else if (char_length
> 1 && g_unichar_isprint (utf_ch
))
2805 col
-= char_length
- 1;
2808 c
= convert_to_display_c (c
);
2812 return (upto
!= 0 ? (off_t
) col
: p
);
2814 col
+= TAB_SIZE
- col
% TAB_SIZE
;
2815 else if ((c
< 32 || c
== 127) && (orig_c
== c
2817 || (!mc_global
.utf8_display
&& !edit
->utf8
)
2820 /* '\r' is shown as ^M, so we must advance 2 characters */
2821 /* Caret notation for control characters */
2829 /* --------------------------------------------------------------------------------------------- */
2830 /** returns the current offset of the cursor from the beginning of a file */
2833 edit_get_cursor_offset (const WEdit
* edit
)
2835 return edit
->buffer
.curs1
;
2838 /* --------------------------------------------------------------------------------------------- */
2839 /** returns the current column position of the cursor */
2842 edit_get_col (const WEdit
* edit
)
2844 return (long) edit_move_forward3 (edit
, edit_buffer_get_current_bol (&edit
->buffer
), 0,
2845 edit
->buffer
.curs1
);
2848 /* --------------------------------------------------------------------------------------------- */
2849 /* Scrolling functions */
2850 /* --------------------------------------------------------------------------------------------- */
2853 edit_update_curs_row (WEdit
* edit
)
2855 edit
->curs_row
= edit
->buffer
.curs_line
- edit
->start_line
;
2858 /* --------------------------------------------------------------------------------------------- */
2861 edit_update_curs_col (WEdit
* edit
)
2863 edit
->curs_col
= (long) edit_move_forward3 (edit
, edit_buffer_get_current_bol (&edit
->buffer
),
2864 0, edit
->buffer
.curs1
);
2867 /* --------------------------------------------------------------------------------------------- */
2870 edit_get_curs_col (const WEdit
* edit
)
2872 return edit
->curs_col
;
2875 /* --------------------------------------------------------------------------------------------- */
2876 /** moves the display start position up by i lines */
2879 edit_scroll_upward (WEdit
* edit
, long i
)
2881 long lines_above
= edit
->start_line
;
2883 if (i
> lines_above
)
2887 edit
->start_line
-= i
;
2888 edit
->start_display
=
2889 edit_buffer_get_backward_offset (&edit
->buffer
, edit
->start_display
, i
);
2890 edit
->force
|= REDRAW_PAGE
;
2891 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
2893 edit_update_curs_row (edit
);
2897 /* --------------------------------------------------------------------------------------------- */
2900 edit_scroll_downward (WEdit
* edit
, long i
)
2904 lines_below
= edit
->buffer
.lines
- edit
->start_line
- (WIDGET (edit
)->lines
- 1);
2905 if (lines_below
> 0)
2907 if (i
> lines_below
)
2909 edit
->start_line
+= i
;
2910 edit
->start_display
=
2911 edit_buffer_get_forward_offset (&edit
->buffer
, edit
->start_display
, i
, 0);
2912 edit
->force
|= REDRAW_PAGE
;
2913 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
2915 edit_update_curs_row (edit
);
2918 /* --------------------------------------------------------------------------------------------- */
2921 edit_scroll_right (WEdit
* edit
, long i
)
2923 edit
->force
|= REDRAW_PAGE
;
2924 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
2925 edit
->start_col
-= i
;
2928 /* --------------------------------------------------------------------------------------------- */
2931 edit_scroll_left (WEdit
* edit
, long i
)
2933 if (edit
->start_col
)
2935 edit
->start_col
+= i
;
2936 if (edit
->start_col
> 0)
2937 edit
->start_col
= 0;
2938 edit
->force
|= REDRAW_PAGE
;
2939 edit
->force
&= (0xfff - REDRAW_CHAR_ONLY
);
2943 /* --------------------------------------------------------------------------------------------- */
2944 /* high level cursor movement commands */
2945 /* --------------------------------------------------------------------------------------------- */
2948 edit_move_to_prev_col (WEdit
* edit
, off_t p
)
2950 long prev
= edit
->prev_col
;
2951 long over
= edit
->over_col
;
2953 edit_cursor_move (edit
,
2954 edit_move_forward3 (edit
, p
, prev
+ edit
->over_col
, 0) - edit
->buffer
.curs1
);
2956 if (option_cursor_beyond_eol
)
2960 line_len
= (long) edit_move_forward3 (edit
, edit_buffer_get_current_bol (&edit
->buffer
), 0,
2961 edit_buffer_get_current_eol (&edit
->buffer
));
2962 if (line_len
< prev
+ edit
->over_col
)
2964 edit
->over_col
= prev
+ over
- line_len
;
2965 edit
->prev_col
= line_len
;
2966 edit
->curs_col
= line_len
;
2970 edit
->curs_col
= prev
+ over
;
2971 edit
->prev_col
= edit
->curs_col
;
2978 if (option_fake_half_tabs
&& is_in_indent (&edit
->buffer
))
2980 long fake_half_tabs
;
2982 edit_update_curs_col (edit
);
2984 fake_half_tabs
= HALF_TAB_SIZE
* space_width
;
2985 if (fake_half_tabs
!= 0 && edit
->curs_col
% fake_half_tabs
!= 0)
2990 edit
->curs_col
-= (edit
->curs_col
% fake_half_tabs
);
2991 p
= edit_buffer_get_current_bol (&edit
->buffer
);
2992 edit_cursor_move (edit
,
2993 edit_move_forward3 (edit
, p
, edit
->curs_col
,
2994 0) - edit
->buffer
.curs1
);
2995 if (!left_of_four_spaces (edit
))
2996 edit_cursor_move (edit
,
2997 edit_move_forward3 (edit
, p
, q
, 0) - edit
->buffer
.curs1
);
3003 /* --------------------------------------------------------------------------------------------- */
3004 /** check whether line in editor is blank or not
3006 * @param edit editor object
3007 * @param line number of line
3009 * @return TRUE if line in blank, FALSE otherwise
3013 edit_line_is_blank (WEdit
* edit
, long line
)
3015 return is_blank (&edit
->buffer
, edit_find_line (edit
, line
));
3018 /* --------------------------------------------------------------------------------------------- */
3019 /** move cursor to line 'line' */
3022 edit_move_to_line (WEdit
* e
, long line
)
3024 if (line
< e
->buffer
.curs_line
)
3025 edit_move_up (e
, e
->buffer
.curs_line
- line
, FALSE
);
3027 edit_move_down (e
, line
- e
->buffer
.curs_line
, FALSE
);
3028 edit_scroll_screen_over_cursor (e
);
3031 /* --------------------------------------------------------------------------------------------- */
3032 /** scroll window so that first visible line is 'line' */
3035 edit_move_display (WEdit
* e
, long line
)
3037 if (line
< e
->start_line
)
3038 edit_scroll_upward (e
, e
->start_line
- line
);
3040 edit_scroll_downward (e
, line
- e
->start_line
);
3043 /* --------------------------------------------------------------------------------------------- */
3044 /** save markers onto undo stack */
3047 edit_push_markers (WEdit
* edit
)
3049 edit_push_undo_action (edit
, MARK_1
+ edit
->mark1
);
3050 edit_push_undo_action (edit
, MARK_2
+ edit
->mark2
);
3051 edit_push_undo_action (edit
, MARK_CURS
+ edit
->end_mark_curs
);
3054 /* --------------------------------------------------------------------------------------------- */
3057 edit_set_markers (WEdit
* edit
, off_t m1
, off_t m2
, long c1
, long c2
)
3066 /* --------------------------------------------------------------------------------------------- */
3067 /** highlight marker toggle */
3070 edit_mark_cmd (WEdit
* edit
, gboolean unmark
)
3072 edit_push_markers (edit
);
3075 edit_set_markers (edit
, 0, 0, 0, 0);
3076 edit
->force
|= REDRAW_PAGE
;
3078 else if (edit
->mark2
>= 0)
3080 edit
->end_mark_curs
= -1;
3081 edit_set_markers (edit
, edit
->buffer
.curs1
, -1, edit
->curs_col
+ edit
->over_col
,
3082 edit
->curs_col
+ edit
->over_col
);
3083 edit
->force
|= REDRAW_PAGE
;
3087 edit
->end_mark_curs
= edit
->buffer
.curs1
;
3088 edit_set_markers (edit
, edit
->mark1
, edit
->buffer
.curs1
, edit
->column1
,
3089 edit
->curs_col
+ edit
->over_col
);
3093 /* --------------------------------------------------------------------------------------------- */
3094 /** highlight the word under cursor */
3097 edit_mark_current_word_cmd (WEdit
* edit
)
3101 for (pos
= edit
->buffer
.curs1
; pos
!= 0; pos
--)
3105 c1
= edit_buffer_get_byte (&edit
->buffer
, pos
);
3106 c2
= edit_buffer_get_byte (&edit
->buffer
, pos
- 1);
3107 if (!isspace (c1
) && isspace (c2
))
3109 if ((my_type_of (c1
) & my_type_of (c2
)) == 0)
3114 for (; pos
< edit
->buffer
.size
; pos
++)
3118 c1
= edit_buffer_get_byte (&edit
->buffer
, pos
);
3119 c2
= edit_buffer_get_byte (&edit
->buffer
, pos
+ 1);
3120 if (!isspace (c1
) && isspace (c2
))
3122 if ((my_type_of (c1
) & my_type_of (c2
)) == 0)
3125 edit
->mark2
= MIN (pos
+ 1, edit
->buffer
.size
);
3127 edit
->force
|= REDRAW_LINE_ABOVE
| REDRAW_AFTER_CURSOR
;
3130 /* --------------------------------------------------------------------------------------------- */
3133 edit_mark_current_line_cmd (WEdit
* edit
)
3135 edit
->mark1
= edit_buffer_get_current_bol (&edit
->buffer
);
3136 edit
->mark2
= edit_buffer_get_current_eol (&edit
->buffer
);
3138 edit
->force
|= REDRAW_LINE_ABOVE
| REDRAW_AFTER_CURSOR
;
3141 /* --------------------------------------------------------------------------------------------- */
3144 edit_delete_line (WEdit
* edit
)
3147 * Delete right part of the line.
3148 * Note that edit_buffer_get_byte() returns '\n' when byte position is
3151 while (edit_buffer_get_current_byte (&edit
->buffer
) != '\n')
3152 (void) edit_delete (edit
, TRUE
);
3156 * Note that edit_delete() will not corrupt anything if called while
3157 * cursor position is EOF.
3159 (void) edit_delete (edit
, TRUE
);
3162 * Delete left part of the line.
3163 * Note, that edit_buffer_get_byte() returns '\n' when byte position is < 0.
3165 while (edit_buffer_get_previous_byte (&edit
->buffer
) != '\n')
3166 (void) edit_backspace (edit
, TRUE
);
3169 /* --------------------------------------------------------------------------------------------- */
3172 edit_push_key_press (WEdit
* edit
)
3174 edit_push_undo_action (edit
, KEY_PRESS
+ edit
->start_display
);
3175 if (edit
->mark2
== -1)
3177 edit_push_undo_action (edit
, MARK_1
+ edit
->mark1
);
3178 edit_push_undo_action (edit
, MARK_CURS
+ edit
->end_mark_curs
);
3182 /* --------------------------------------------------------------------------------------------- */
3185 edit_find_bracket (WEdit
* edit
)
3187 edit
->bracket
= edit_get_bracket (edit
, 1, 10000);
3188 if (edit
->last_bracket
!= edit
->bracket
)
3189 edit
->force
|= REDRAW_PAGE
;
3190 edit
->last_bracket
= edit
->bracket
;
3193 /* --------------------------------------------------------------------------------------------- */
3195 * This executes a command as though the user initiated it through a key
3196 * press. Callback with MSG_KEY as a message calls this after
3197 * translating the key press. This function can be used to pass any
3198 * command to the editor. Note that the screen wouldn't update
3199 * automatically. Either of command or char_for_insertion must be
3200 * passed as -1. Commands are executed, and char_for_insertion is
3201 * inserted at the cursor.
3205 edit_execute_key_command (WEdit
* edit
, long command
, int char_for_insertion
)
3207 if (command
== CK_MacroStartRecord
|| command
== CK_RepeatStartRecord
3209 && (command
== CK_MacroStartStopRecord
|| command
== CK_RepeatStartStopRecord
)))
3212 edit
->force
|= REDRAW_CHAR_ONLY
| REDRAW_LINE
;
3215 if (macro_index
!= -1)
3217 edit
->force
|= REDRAW_COMPLETELY
;
3218 if (command
== CK_MacroStopRecord
|| command
== CK_MacroStartStopRecord
)
3220 edit_store_macro_cmd (edit
);
3224 if (command
== CK_RepeatStopRecord
|| command
== CK_RepeatStartStopRecord
)
3226 edit_repeat_macro_cmd (edit
);
3232 if (macro_index
>= 0 && macro_index
< MAX_MACRO_LENGTH
- 1)
3234 record_macro_buf
[macro_index
].action
= command
;
3235 record_macro_buf
[macro_index
++].ch
= char_for_insertion
;
3237 /* record the beginning of a set of editing actions initiated by a key press */
3238 if (command
!= CK_Undo
&& command
!= CK_ExtendedKeyMap
)
3239 edit_push_key_press (edit
);
3241 edit_execute_cmd (edit
, command
, char_for_insertion
);
3242 if (edit
->column_highlight
)
3243 edit
->force
|= REDRAW_PAGE
;
3246 /* --------------------------------------------------------------------------------------------- */
3248 This executes a command at a lower level than macro recording.
3249 It also does not push a key_press onto the undo stack. This means
3250 that if it is called many times, a single undo command will undo
3251 all of them. It also does not check for the Undo command.
3254 edit_execute_cmd (WEdit
* edit
, long command
, int char_for_insertion
)
3256 Widget
*w
= WIDGET (edit
);
3258 if (command
== CK_WindowFullscreen
)
3260 edit_toggle_fullscreen (edit
);
3264 /* handle window state */
3265 if (edit_handle_move_resize (edit
, command
))
3268 edit
->force
|= REDRAW_LINE
;
3270 /* The next key press will unhighlight the found string, so update
3272 if (edit
->found_len
|| edit
->column_highlight
)
3273 edit
->force
|= REDRAW_PAGE
;
3277 /* a mark command with shift-arrow */
3280 case CK_MarkToWordBegin
:
3281 case CK_MarkToWordEnd
:
3287 case CK_MarkPageDown
:
3288 case CK_MarkToFileBegin
:
3289 case CK_MarkToFileEnd
:
3290 case CK_MarkToPageBegin
:
3291 case CK_MarkToPageEnd
:
3292 case CK_MarkScrollUp
:
3293 case CK_MarkScrollDown
:
3294 case CK_MarkParagraphUp
:
3295 case CK_MarkParagraphDown
:
3296 /* a mark command with alt-arrow */
3297 case CK_MarkColumnPageUp
:
3298 case CK_MarkColumnPageDown
:
3299 case CK_MarkColumnLeft
:
3300 case CK_MarkColumnRight
:
3301 case CK_MarkColumnUp
:
3302 case CK_MarkColumnDown
:
3303 case CK_MarkColumnScrollUp
:
3304 case CK_MarkColumnScrollDown
:
3305 case CK_MarkColumnParagraphUp
:
3306 case CK_MarkColumnParagraphDown
:
3307 edit
->column_highlight
= 0;
3308 if (edit
->highlight
== 0 || (edit
->mark2
!= -1 && edit
->mark1
!= edit
->mark2
))
3310 edit_mark_cmd (edit
, TRUE
); /* clear */
3311 edit_mark_cmd (edit
, FALSE
); /* marking on */
3313 edit
->highlight
= 1;
3316 /* any other command */
3318 if (edit
->highlight
)
3319 edit_mark_cmd (edit
, FALSE
); /* clear */
3320 edit
->highlight
= 0;
3323 /* first check for undo */
3324 if (command
== CK_Undo
)
3326 edit
->redo_stack_reset
= 0;
3327 edit_group_undo (edit
);
3328 edit
->found_len
= 0;
3329 edit
->prev_col
= edit_get_col (edit
);
3330 edit
->search_start
= edit
->buffer
.curs1
;
3333 /* check for redo */
3334 if (command
== CK_Redo
)
3336 edit
->redo_stack_reset
= 0;
3337 edit_do_redo (edit
);
3338 edit
->found_len
= 0;
3339 edit
->prev_col
= edit_get_col (edit
);
3340 edit
->search_start
= edit
->buffer
.curs1
;
3344 edit
->redo_stack_reset
= 1;
3346 /* An ordinary key press */
3347 if (char_for_insertion
>= 0)
3349 /* if non persistent selection and text selected */
3350 if (!option_persistent_selections
&& edit
->mark1
!= edit
->mark2
)
3351 edit_block_delete_cmd (edit
);
3353 if (edit
->overwrite
)
3355 /* remove char only one time, after input first byte, multibyte chars */
3357 if (!mc_global
.utf8_display
|| edit
->charpoint
== 0)
3359 if (edit_buffer_get_current_byte (&edit
->buffer
) != '\n')
3361 edit_delete (edit
, FALSE
);
3363 if (option_cursor_beyond_eol
&& edit
->over_col
> 0)
3364 edit_insert_over (edit
);
3367 Encode 8-bit input as UTF-8, if display (locale) is *not* UTF-8,
3368 *but* source encoding *is* set to UTF-8; see ticket #3843 for the details.
3370 if (char_for_insertion
> 127 && str_isutf8 (get_codepage_id (mc_global
.source_codepage
))
3371 && !mc_global
.utf8_display
)
3373 unsigned char str
[UTF8_CHAR_LEN
+ 1];
3377 res
= g_unichar_to_utf8 (char_for_insertion
, (char *) str
);
3387 while (i
<= UTF8_CHAR_LEN
&& str
[i
] != '\0')
3389 char_for_insertion
= str
[i
];
3390 edit_insert (edit
, char_for_insertion
);
3396 edit_insert (edit
, char_for_insertion
);
3398 if (option_auto_para_formatting
)
3400 format_paragraph (edit
, FALSE
);
3401 edit
->force
|= REDRAW_PAGE
;
3404 check_and_wrap_line (edit
);
3405 edit
->found_len
= 0;
3406 edit
->prev_col
= edit_get_col (edit
);
3407 edit
->search_start
= edit
->buffer
.curs1
;
3408 edit_find_bracket (edit
);
3414 case CK_TopOnScreen
:
3415 case CK_BottomOnScreen
:
3428 if (!option_persistent_selections
&& edit
->mark2
>= 0)
3430 if (edit
->column_highlight
)
3431 edit_push_undo_action (edit
, COLUMN_ON
);
3432 edit
->column_highlight
= 0;
3433 edit_mark_cmd (edit
, TRUE
);
3441 case CK_TopOnScreen
:
3442 case CK_BottomOnScreen
:
3443 case CK_MarkToPageBegin
:
3444 case CK_MarkToPageEnd
:
3449 case CK_MarkToWordBegin
:
3450 case CK_MarkToWordEnd
:
3453 case CK_MarkColumnUp
:
3454 case CK_MarkColumnDown
:
3455 if (edit
->mark2
== -1)
3456 break; /*marking is following the cursor: may need to highlight a whole line */
3462 edit
->force
|= REDRAW_CHAR_ONLY
;
3467 /* basic cursor key commands */
3471 /* if non persistent selection and text selected */
3472 if (!option_persistent_selections
&& edit
->mark1
!= edit
->mark2
)
3473 edit_block_delete_cmd (edit
);
3474 else if (option_cursor_beyond_eol
&& edit
->over_col
> 0)
3476 else if (option_backspace_through_tabs
&& is_in_indent (&edit
->buffer
))
3478 while (edit_buffer_get_previous_byte (&edit
->buffer
) != '\n' && edit
->buffer
.curs1
> 0)
3479 edit_backspace (edit
, TRUE
);
3481 else if (option_fake_half_tabs
&& is_in_indent (&edit
->buffer
)
3482 && right_of_four_spaces (edit
))
3486 for (i
= 0; i
< HALF_TAB_SIZE
; i
++)
3487 edit_backspace (edit
, TRUE
);
3490 edit_backspace (edit
, FALSE
);
3493 /* if non persistent selection and text selected */
3494 if (!option_persistent_selections
&& edit
->mark1
!= edit
->mark2
)
3495 edit_block_delete_cmd (edit
);
3498 if (option_cursor_beyond_eol
&& edit
->over_col
> 0)
3499 edit_insert_over (edit
);
3501 if (option_fake_half_tabs
&& is_in_indent (&edit
->buffer
) && left_of_four_spaces (edit
))
3505 for (i
= 1; i
<= HALF_TAB_SIZE
; i
++)
3506 edit_delete (edit
, TRUE
);
3509 edit_delete (edit
, FALSE
);
3512 case CK_DeleteToWordBegin
:
3514 edit_left_delete_word (edit
);
3516 case CK_DeleteToWordEnd
:
3517 if (option_cursor_beyond_eol
&& edit
->over_col
> 0)
3518 edit_insert_over (edit
);
3520 edit_right_delete_word (edit
);
3523 edit_delete_line (edit
);
3525 case CK_DeleteToHome
:
3526 edit_delete_to_line_begin (edit
);
3528 case CK_DeleteToEnd
:
3529 edit_delete_to_line_end (edit
);
3533 if (option_auto_para_formatting
)
3535 edit_double_newline (edit
);
3536 if (option_return_does_auto_indent
&& !bracketed_pasting_in_progress
)
3537 edit_auto_indent (edit
);
3538 format_paragraph (edit
, FALSE
);
3542 edit_insert (edit
, '\n');
3543 if (option_return_does_auto_indent
&& !bracketed_pasting_in_progress
)
3544 edit_auto_indent (edit
);
3548 edit_insert (edit
, '\n');
3551 case CK_MarkColumnPageUp
:
3552 edit
->column_highlight
= 1;
3556 edit_move_up (edit
, w
->lines
- 1, TRUE
);
3558 case CK_MarkColumnPageDown
:
3559 edit
->column_highlight
= 1;
3562 case CK_MarkPageDown
:
3563 edit_move_down (edit
, w
->lines
- 1, TRUE
);
3565 case CK_MarkColumnLeft
:
3566 edit
->column_highlight
= 1;
3570 if (option_fake_half_tabs
&& is_in_indent (&edit
->buffer
) && right_of_four_spaces (edit
))
3572 if (option_cursor_beyond_eol
&& edit
->over_col
> 0)
3575 edit_cursor_move (edit
, -HALF_TAB_SIZE
);
3576 edit
->force
&= (0xFFF - REDRAW_CHAR_ONLY
);
3579 edit_left_char_move_cmd (edit
);
3581 case CK_MarkColumnRight
:
3582 edit
->column_highlight
= 1;
3586 if (option_fake_half_tabs
&& is_in_indent (&edit
->buffer
) && left_of_four_spaces (edit
))
3588 edit_cursor_move (edit
, HALF_TAB_SIZE
);
3589 edit
->force
&= (0xFFF - REDRAW_CHAR_ONLY
);
3592 edit_right_char_move_cmd (edit
);
3594 case CK_TopOnScreen
:
3595 case CK_MarkToPageBegin
:
3596 edit_begin_page (edit
);
3598 case CK_BottomOnScreen
:
3599 case CK_MarkToPageEnd
:
3600 edit_end_page (edit
);
3603 case CK_MarkToWordBegin
:
3605 edit_left_word_move_cmd (edit
);
3608 case CK_MarkToWordEnd
:
3610 edit_right_word_move_cmd (edit
);
3612 case CK_MarkColumnUp
:
3613 edit
->column_highlight
= 1;
3617 edit_move_up (edit
, 1, FALSE
);
3619 case CK_MarkColumnDown
:
3620 edit
->column_highlight
= 1;
3624 edit_move_down (edit
, 1, FALSE
);
3626 case CK_MarkColumnParagraphUp
:
3627 edit
->column_highlight
= 1;
3629 case CK_ParagraphUp
:
3630 case CK_MarkParagraphUp
:
3631 edit_move_up_paragraph (edit
, FALSE
);
3633 case CK_MarkColumnParagraphDown
:
3634 edit
->column_highlight
= 1;
3636 case CK_ParagraphDown
:
3637 case CK_MarkParagraphDown
:
3638 edit_move_down_paragraph (edit
, FALSE
);
3640 case CK_MarkColumnScrollUp
:
3641 edit
->column_highlight
= 1;
3644 case CK_MarkScrollUp
:
3645 edit_move_up (edit
, 1, TRUE
);
3647 case CK_MarkColumnScrollDown
:
3648 edit
->column_highlight
= 1;
3651 case CK_MarkScrollDown
:
3652 edit_move_down (edit
, 1, TRUE
);
3656 edit_cursor_to_bol (edit
);
3660 edit_cursor_to_eol (edit
);
3663 /* if text marked shift block */
3664 if (edit
->mark1
!= edit
->mark2
&& !option_persistent_selections
)
3666 if (edit
->mark2
< 0)
3667 edit_mark_cmd (edit
, FALSE
);
3668 edit_move_block_to_right (edit
);
3672 if (option_cursor_beyond_eol
)
3673 edit_insert_over (edit
);
3674 edit_tab_cmd (edit
);
3675 if (option_auto_para_formatting
)
3677 format_paragraph (edit
, FALSE
);
3678 edit
->force
|= REDRAW_PAGE
;
3681 check_and_wrap_line (edit
);
3685 case CK_InsertOverwrite
:
3686 edit
->overwrite
= !edit
->overwrite
;
3690 if (edit
->mark2
>= 0)
3692 if (edit
->column_highlight
)
3693 edit_push_undo_action (edit
, COLUMN_ON
);
3694 edit
->column_highlight
= 0;
3696 edit_mark_cmd (edit
, FALSE
);
3699 if (!edit
->column_highlight
)
3700 edit_push_undo_action (edit
, COLUMN_OFF
);
3701 edit
->column_highlight
= 1;
3702 edit_mark_cmd (edit
, FALSE
);
3705 edit_set_markers (edit
, 0, edit
->buffer
.size
, 0, 0);
3706 edit
->force
|= REDRAW_PAGE
;
3709 if (edit
->column_highlight
)
3710 edit_push_undo_action (edit
, COLUMN_ON
);
3711 edit
->column_highlight
= 0;
3712 edit_mark_cmd (edit
, TRUE
);
3715 if (edit
->column_highlight
)
3716 edit_push_undo_action (edit
, COLUMN_ON
);
3717 edit
->column_highlight
= 0;
3718 edit_mark_current_word_cmd (edit
);
3721 if (edit
->column_highlight
)
3722 edit_push_undo_action (edit
, COLUMN_ON
);
3723 edit
->column_highlight
= 0;
3724 edit_mark_current_line_cmd (edit
);
3728 book_mark_clear (edit
, edit
->buffer
.curs_line
, BOOK_MARK_FOUND_COLOR
);
3729 if (book_mark_query_color (edit
, edit
->buffer
.curs_line
, BOOK_MARK_COLOR
))
3730 book_mark_clear (edit
, edit
->buffer
.curs_line
, BOOK_MARK_COLOR
);
3732 book_mark_insert (edit
, edit
->buffer
.curs_line
, BOOK_MARK_COLOR
);
3734 case CK_BookmarkFlush
:
3735 book_mark_flush (edit
, BOOK_MARK_COLOR
);
3736 book_mark_flush (edit
, BOOK_MARK_FOUND_COLOR
);
3737 edit
->force
|= REDRAW_PAGE
;
3739 case CK_BookmarkNext
:
3740 if (edit
->book_mark
!= NULL
)
3742 edit_book_mark_t
*p
;
3744 p
= book_mark_find (edit
, edit
->buffer
.curs_line
);
3745 if (p
->next
!= NULL
)
3748 if (p
->line
>= edit
->start_line
+ w
->lines
|| p
->line
< edit
->start_line
)
3749 edit_move_display (edit
, p
->line
- w
->lines
/ 2);
3750 edit_move_to_line (edit
, p
->line
);
3754 case CK_BookmarkPrev
:
3755 if (edit
->book_mark
!= NULL
)
3757 edit_book_mark_t
*p
;
3759 p
= book_mark_find (edit
, edit
->buffer
.curs_line
);
3760 while (p
->line
== edit
->buffer
.curs_line
)
3761 if (p
->prev
!= NULL
)
3765 if (p
->line
>= edit
->start_line
+ w
->lines
|| p
->line
< edit
->start_line
)
3766 edit_move_display (edit
, p
->line
- w
->lines
/ 2);
3767 edit_move_to_line (edit
, p
->line
);
3773 case CK_MarkToFileBegin
:
3774 edit_move_to_top (edit
);
3777 case CK_MarkToFileEnd
:
3778 edit_move_to_bottom (edit
);
3782 if (option_cursor_beyond_eol
&& edit
->over_col
> 0)
3783 edit_insert_over (edit
);
3784 edit_block_copy_cmd (edit
);
3787 edit_block_delete_cmd (edit
);
3790 edit_block_move_cmd (edit
);
3793 case CK_BlockShiftLeft
:
3794 if (edit
->mark1
!= edit
->mark2
)
3795 edit_move_block_to_left (edit
);
3797 case CK_BlockShiftRight
:
3798 if (edit
->mark1
!= edit
->mark2
)
3799 edit_move_block_to_right (edit
);
3802 edit_copy_to_X_buf_cmd (edit
);
3805 edit_cut_to_X_buf_cmd (edit
);
3808 /* if non persistent selection and text selected */
3809 if (!option_persistent_selections
&& edit
->mark1
!= edit
->mark2
)
3810 edit_block_delete_cmd (edit
);
3811 if (option_cursor_beyond_eol
&& edit
->over_col
> 0)
3812 edit_insert_over (edit
);
3813 edit_paste_from_X_buf_cmd (edit
);
3814 if (!option_persistent_selections
&& edit
->mark2
>= 0)
3816 if (edit
->column_highlight
)
3817 edit_push_undo_action (edit
, COLUMN_ON
);
3818 edit
->column_highlight
= 0;
3819 edit_mark_cmd (edit
, TRUE
);
3823 edit_paste_from_history (edit
);
3827 edit_save_as_cmd (edit
);
3830 edit_save_confirm_cmd (edit
);
3833 edit_save_block_cmd (edit
);
3836 edit_insert_file_cmd (edit
);
3840 edit_load_back_cmd (edit
);
3843 edit_load_forward_cmd (edit
);
3846 case CK_SyntaxChoose
:
3847 edit_syntax_dialog (edit
);
3851 edit_search_cmd (edit
, FALSE
);
3853 case CK_SearchContinue
:
3854 edit_search_cmd (edit
, TRUE
);
3857 edit_replace_cmd (edit
, FALSE
);
3859 case CK_ReplaceContinue
:
3860 edit_replace_cmd (edit
, TRUE
);
3863 /* if text marked shift block */
3864 if (edit
->mark1
!= edit
->mark2
&& !option_persistent_selections
)
3865 edit_move_block_to_left (edit
);
3867 edit_complete_word_cmd (edit
);
3870 edit_get_match_keyword_cmd (edit
);
3874 case CK_SpellCheckCurrentWord
:
3875 edit_suggest_current_word (edit
);
3878 edit_spellcheck_file (edit
);
3880 case CK_SpellCheckSelectLang
:
3881 edit_set_spell_lang ();
3888 /* fool gcc to prevent a Y2K warning */
3889 char time_format
[] = "_c";
3890 time_format
[0] = '%';
3892 FMT_LOCALTIME_CURRENT (s
, sizeof (s
), time_format
);
3893 edit_print_string (edit
, s
);
3894 edit
->force
|= REDRAW_PAGE
;
3898 edit_goto_cmd (edit
);
3900 case CK_ParagraphFormat
:
3901 format_paragraph (edit
, TRUE
);
3902 edit
->force
|= REDRAW_PAGE
;
3904 case CK_MacroDelete
:
3905 edit_delete_macro_cmd (edit
);
3907 case CK_MatchBracket
:
3908 edit_goto_matching_bracket (edit
);
3911 user_menu (edit
, NULL
, -1);
3914 edit_sort_cmd (edit
);
3916 case CK_ExternalCommand
:
3917 edit_ext_cmd (edit
);
3920 edit_mail_dialog (edit
);
3923 case CK_SelectCodepage
:
3924 edit_select_codepage_cmd (edit
);
3927 case CK_InsertLiteral
:
3928 edit_insert_literal_cmd (edit
);
3930 case CK_MacroStartStopRecord
:
3931 edit_begin_end_macro_cmd (edit
);
3933 case CK_RepeatStartStopRecord
:
3934 edit_begin_end_repeat_cmd (edit
);
3936 case CK_ExtendedKeyMap
:
3937 edit
->extmod
= TRUE
;
3944 if ((command
/ CK_PipeBlock (0)) == 1)
3945 edit_block_process_cmd (edit
, command
- CK_PipeBlock (0));
3947 /* keys which must set the col position, and the search vars */
3951 case CK_SearchContinue
:
3953 case CK_ReplaceContinue
:
3955 edit
->prev_col
= edit_get_col (edit
);
3959 case CK_MarkColumnUp
:
3962 case CK_MarkColumnDown
:
3965 case CK_MarkColumnPageUp
:
3967 case CK_MarkPageDown
:
3968 case CK_MarkColumnPageDown
:
3970 case CK_MarkToFileBegin
:
3972 case CK_MarkToFileEnd
:
3973 case CK_ParagraphUp
:
3974 case CK_MarkParagraphUp
:
3975 case CK_MarkColumnParagraphUp
:
3976 case CK_ParagraphDown
:
3977 case CK_MarkParagraphDown
:
3978 case CK_MarkColumnParagraphDown
:
3980 case CK_MarkScrollUp
:
3981 case CK_MarkColumnScrollUp
:
3983 case CK_MarkScrollDown
:
3984 case CK_MarkColumnScrollDown
:
3985 edit
->search_start
= edit
->buffer
.curs1
;
3986 edit
->found_len
= 0;
3989 edit
->found_len
= 0;
3990 edit
->prev_col
= edit_get_col (edit
);
3991 edit
->search_start
= edit
->buffer
.curs1
;
3993 edit_find_bracket (edit
);
3995 if (option_auto_para_formatting
)
4001 case CK_DeleteToWordBegin
:
4002 case CK_DeleteToWordEnd
:
4003 case CK_DeleteToHome
:
4004 case CK_DeleteToEnd
:
4005 format_paragraph (edit
, FALSE
);
4006 edit
->force
|= REDRAW_PAGE
;
4013 /* --------------------------------------------------------------------------------------------- */
4016 edit_stack_init (void)
4018 for (edit_stack_iterator
= 0; edit_stack_iterator
< MAX_HISTORY_MOVETO
; edit_stack_iterator
++)
4020 edit_history_moveto
[edit_stack_iterator
].filename_vpath
= NULL
;
4021 edit_history_moveto
[edit_stack_iterator
].line
= -1;
4024 edit_stack_iterator
= 0;
4027 /* --------------------------------------------------------------------------------------------- */
4030 edit_stack_free (void)
4032 for (edit_stack_iterator
= 0; edit_stack_iterator
< MAX_HISTORY_MOVETO
; edit_stack_iterator
++)
4033 vfs_path_free (edit_history_moveto
[edit_stack_iterator
].filename_vpath
);
4036 /* --------------------------------------------------------------------------------------------- */
4040 edit_move_up (WEdit
* edit
, long i
, gboolean do_scroll
)
4042 edit_move_updown (edit
, i
, do_scroll
, TRUE
);
4045 /* --------------------------------------------------------------------------------------------- */
4049 edit_move_down (WEdit
* edit
, long i
, gboolean do_scroll
)
4051 edit_move_updown (edit
, i
, do_scroll
, FALSE
);
4054 /* --------------------------------------------------------------------------------------------- */