root/src/editor/edit.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. edit_load_status_update_cb
  2. edit_load_file_fast
  3. edit_find_filter
  4. edit_get_filter
  5. edit_insert_stream
  6. check_file_access
  7. edit_load_file
  8. edit_load_position
  9. edit_save_position
  10. edit_purge_widget
  11. edit_pop_undo_action
  12. edit_pop_redo_action
  13. get_prev_undo_action
  14. edit_modification
  15. is_in_indent
  16. is_blank
  17. edit_find_line
  18. edit_move_up_paragraph
  19. edit_move_down_paragraph
  20. edit_begin_page
  21. edit_end_page
  22. edit_move_to_top
  23. edit_move_to_bottom
  24. edit_cursor_to_bol
  25. edit_cursor_to_eol
  26. my_type_of
  27. edit_left_word_move
  28. edit_left_word_move_cmd
  29. edit_right_word_move
  30. edit_right_word_move_cmd
  31. edit_right_char_move_cmd
  32. edit_left_char_move_cmd
  33. edit_move_updown
  34. edit_right_delete_word
  35. edit_left_delete_word
  36. edit_do_undo
  37. edit_do_redo
  38. edit_group_undo
  39. edit_delete_to_line_end
  40. edit_delete_to_line_begin
  41. is_aligned_on_a_tab
  42. right_of_four_spaces
  43. left_of_four_spaces
  44. edit_auto_indent
  45. edit_double_newline
  46. insert_spaces_tab
  47. edit_tab_cmd
  48. check_and_wrap_line
  49. edit_get_bracket
  50. edit_goto_matching_bracket
  51. edit_move_block_to_right
  52. edit_move_block_to_left
  53. edit_print_string
  54. edit_insert_column_from_file
  55. user_menu
  56. edit_get_write_filter
  57. edit_write_stream
  58. is_break_char
  59. edit_insert_file
  60. edit_init
  61. edit_clean
  62. edit_reload_line
  63. edit_set_codeset
  64. edit_push_undo_action
  65. edit_push_redo_action
  66. edit_insert
  67. edit_insert_ahead
  68. edit_insert_over
  69. edit_delete
  70. edit_backspace
  71. edit_cursor_move
  72. edit_move_forward3
  73. edit_get_cursor_offset
  74. edit_get_col
  75. edit_update_curs_row
  76. edit_update_curs_col
  77. edit_get_curs_col
  78. edit_scroll_upward
  79. edit_scroll_downward
  80. edit_scroll_right
  81. edit_scroll_left
  82. edit_move_to_prev_col
  83. edit_line_is_blank
  84. edit_move_to_line
  85. edit_move_display
  86. edit_push_markers
  87. edit_set_markers
  88. edit_mark_cmd
  89. edit_mark_current_word_cmd
  90. edit_mark_current_line_cmd
  91. edit_delete_line
  92. edit_push_key_press
  93. edit_find_bracket
  94. edit_execute_key_command
  95. edit_execute_cmd
  96. edit_stack_init
  97. edit_stack_free
  98. edit_move_up
  99. edit_move_down

   1 /*
   2    Editor low level data handling and cursor fundamentals.
   3 
   4    Copyright (C) 1996-2022
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Paul Sheer 1996, 1997
   9    Ilia Maslakov <il.smind@gmail.com> 2009, 2010, 2011
  10    Andrew Borodin <aborodin@vmail.ru> 2012-2022
  11 
  12    This file is part of the Midnight Commander.
  13 
  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.
  18 
  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.
  23 
  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/>.
  26  */
  27 
  28 /** \file
  29  *  \brief Source: editor low level data handling and cursor fundamentals
  30  *  \author Paul Sheer
  31  *  \date 1996, 1997
  32  */
  33 
  34 #include <config.h>
  35 #include <stdio.h>
  36 #include <stdarg.h>
  37 #include <sys/types.h>
  38 #include <unistd.h>
  39 #include <string.h>
  40 #include <ctype.h>
  41 #include <errno.h>
  42 #include <sys/stat.h>
  43 #include <stdint.h>             /* UINTMAX_MAX */
  44 #include <stdlib.h>
  45 
  46 #include "lib/global.h"
  47 
  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_HOME_BLOCK_FILE */
  53 #include "lib/vfs/vfs.h"
  54 #include "lib/strutil.h"        /* utf string functions */
  55 #include "lib/util.h"           /* load_file_position(), save_file_position() */
  56 #include "lib/timefmt.h"        /* time formatting */
  57 #include "lib/lock.h"
  58 #include "lib/widget.h"
  59 
  60 #ifdef HAVE_CHARSET
  61 #include "lib/charsets.h"       /* get_codepage_id */
  62 #endif
  63 
  64 #include "src/usermenu.h"       /* user_menu_cmd() */
  65 
  66 #include "src/setup.h"          /* option_tab_spacing */
  67 #include "src/keymap.h"
  68 
  69 #include "edit-impl.h"
  70 #include "editwidget.h"
  71 #include "editsearch.h"
  72 #include "editcomplete.h"       /* edit_complete_word_cmd() */
  73 #include "editmacros.h"
  74 #include "etags.h"              /* edit_get_match_keyword_cmd() */
  75 #ifdef HAVE_ASPELL
  76 #include "spell.h"
  77 #endif
  78 
  79 /*** global variables ****************************************************************************/
  80 
  81 int option_word_wrap_line_length = DEFAULT_WRAP_LINE_LENGTH;
  82 gboolean option_typewriter_wrap = FALSE;
  83 gboolean option_auto_para_formatting = FALSE;
  84 gboolean option_fill_tabs_with_spaces = FALSE;
  85 gboolean option_return_does_auto_indent = TRUE;
  86 gboolean option_backspace_through_tabs = FALSE;
  87 gboolean option_fake_half_tabs = TRUE;
  88 int option_save_mode = EDIT_QUICK_SAVE;
  89 gboolean option_save_position = TRUE;
  90 int option_max_undo = 32768;
  91 gboolean option_persistent_selections = TRUE;
  92 gboolean option_cursor_beyond_eol = FALSE;
  93 gboolean option_line_state = FALSE;
  94 int option_line_state_width = 0;
  95 gboolean option_cursor_after_inserted_block = FALSE;
  96 gboolean option_state_full_filename = FALSE;
  97 
  98 gboolean enable_show_tabs_tws = TRUE;
  99 gboolean option_check_nl_at_eof = FALSE;
 100 gboolean option_group_undo = FALSE;
 101 gboolean show_right_margin = FALSE;
 102 
 103 char *option_backup_ext = NULL;
 104 char *option_filesize_threshold = NULL;
 105 
 106 unsigned int edit_stack_iterator = 0;
 107 edit_stack_type edit_history_moveto[MAX_HISTORY_MOVETO];
 108 /* magic sequense for say than block is vertical */
 109 const char VERTICAL_MAGIC[] = { '\1', '\1', '\1', '\1', '\n' };
 110 
 111 /*** file scope macro definitions ****************************************************************/
 112 
 113 #define TEMP_BUF_LEN 1024
 114 
 115 #define space_width 1
 116 
 117 /*** file scope type declarations ****************************************************************/
 118 
 119 /*** file scope variables ************************************************************************/
 120 
 121 /* detecting an error on save is easy: just check if every byte has been written. */
 122 /* detecting an error on read, is not so easy 'cos there is not way to tell
 123    whether you read everything or not. */
 124 /* FIXME: add proper 'triple_pipe_open' to read, write and check errors. */
 125 static const struct edit_filters
 126 {
 127     const char *read, *write, *extension;
 128 } all_filters[] =
 129 {
 130     /* *INDENT-OFF* */
 131     { "xz -cd %s 2>&1", "xz > %s", ".xz"},
 132     { "zstd -cd %s 2>&1", "zstd > %s", ".zst"},
 133     { "lz4 -cd %s 2>&1", "lz4 > %s", ".lz4" },
 134     { "lzip -cd %s 2>&1", "lzip > %s", ".lz"},
 135     { "lzma -cd %s 2>&1", "lzma > %s", ".lzma" },
 136     { "bzip2 -cd %s 2>&1", "bzip2 > %s", ".bz2" },
 137     { "gzip -cd %s 2>&1", "gzip > %s", ".gz" },
 138     { "gzip -cd %s 2>&1", "gzip > %s", ".Z" }
 139     /* *INDENT-ON* */
 140 };
 141 
 142 static const off_t option_filesize_default_threshold = 64 * 1024 * 1024;        /* 64 MB */
 143 
 144 /* --------------------------------------------------------------------------------------------- */
 145 /*** file scope functions ************************************************************************/
 146 /* --------------------------------------------------------------------------------------------- */
 147 
 148 static int
 149 edit_load_status_update_cb (status_msg_t * sm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 150 {
 151     simple_status_msg_t *ssm = SIMPLE_STATUS_MSG (sm);
 152     edit_buffer_read_file_status_msg_t *rsm = (edit_buffer_read_file_status_msg_t *) sm;
 153     Widget *wd = WIDGET (sm->dlg);
 154 
 155     if (verbose)
 156         label_set_textv (ssm->label, _("Loading: %3d%%"),
 157                          edit_buffer_calc_percent (rsm->buf, rsm->loaded));
 158     else
 159         label_set_text (ssm->label, _("Loading..."));
 160 
 161     if (rsm->first)
 162     {
 163         Widget *lw = WIDGET (ssm->label);
 164         WRect r;
 165 
 166         r = wd->rect;
 167         r.cols = MAX (r.cols, lw->rect.cols + 6);
 168         widget_set_size_rect (wd, &r);
 169         r = lw->rect;
 170         r.x = wd->rect.x + (wd->rect.cols - r.cols) / 2;
 171         widget_set_size_rect (lw, &r);
 172         rsm->first = FALSE;
 173     }
 174 
 175     return status_msg_common_update (sm);
 176 }
 177 
 178 /* --------------------------------------------------------------------------------------------- */
 179 /**
 180  * Load file OR text into buffers.  Set cursor to the beginning of file.
 181  *
 182  * @return FALSE on error.
 183  */
 184 
 185 static gboolean
 186 edit_load_file_fast (edit_buffer_t * buf, const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 187 {
 188     int file;
 189     gboolean ret;
 190     edit_buffer_read_file_status_msg_t rsm;
 191     gboolean aborted;
 192 
 193     file = mc_open (filename_vpath, O_RDONLY | O_BINARY);
 194     if (file < 0)
 195     {
 196         gchar *errmsg;
 197 
 198         errmsg =
 199             g_strdup_printf (_("Cannot open %s for reading"), vfs_path_as_str (filename_vpath));
 200         edit_error_dialog (_("Error"), errmsg);
 201         g_free (errmsg);
 202         return FALSE;
 203     }
 204 
 205     rsm.first = TRUE;
 206     rsm.buf = buf;
 207     rsm.loaded = 0;
 208 
 209     status_msg_init (STATUS_MSG (&rsm), _("Load file"), 1.0, simple_status_msg_init_cb,
 210                      edit_load_status_update_cb, NULL);
 211 
 212     ret = (edit_buffer_read_file (buf, file, buf->size, &rsm, &aborted) == buf->size);
 213 
 214     status_msg_deinit (STATUS_MSG (&rsm));
 215 
 216     if (!ret && !aborted)
 217     {
 218         gchar *errmsg;
 219 
 220         errmsg = g_strdup_printf (_("Error reading %s"), vfs_path_as_str (filename_vpath));
 221         edit_error_dialog (_("Error"), errmsg);
 222         g_free (errmsg);
 223     }
 224 
 225     mc_close (file);
 226     return ret;
 227 }
 228 
 229 /* --------------------------------------------------------------------------------------------- */
 230 /** Return index of the filter or -1 is there is no appropriate filter */
 231 
 232 static int
 233 edit_find_filter (const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 234 {
 235     size_t i, l;
 236 
 237     if (filename_vpath == NULL)
 238         return -1;
 239 
 240     l = strlen (vfs_path_as_str (filename_vpath));
 241     for (i = 0; i < G_N_ELEMENTS (all_filters); i++)
 242     {
 243         size_t e;
 244 
 245         e = strlen (all_filters[i].extension);
 246         if (l > e)
 247             if (!strcmp (all_filters[i].extension, vfs_path_as_str (filename_vpath) + l - e))
 248                 return i;
 249     }
 250     return -1;
 251 }
 252 
 253 /* --------------------------------------------------------------------------------------------- */
 254 
 255 static char *
 256 edit_get_filter (const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 257 {
 258     int i;
 259     char *p, *quoted_name;
 260 
 261     i = edit_find_filter (filename_vpath);
 262     if (i < 0)
 263         return NULL;
 264 
 265     quoted_name = name_quote (vfs_path_as_str (filename_vpath), FALSE);
 266     p = g_strdup_printf (all_filters[i].read, quoted_name);
 267     g_free (quoted_name);
 268     return p;
 269 }
 270 
 271 /* --------------------------------------------------------------------------------------------- */
 272 
 273 static off_t
 274 edit_insert_stream (WEdit * edit, FILE * f)
     /* [previous][next][first][last][top][bottom][index][help]  */
 275 {
 276     int c;
 277     off_t i = 0;
 278 
 279     while ((c = fgetc (f)) >= 0)
 280     {
 281         edit_insert (edit, c);
 282         i++;
 283     }
 284     return i;
 285 }
 286 
 287 /* --------------------------------------------------------------------------------------------- */
 288 /**
 289   * Open file and create it if necessary.
 290   *
 291   * @param edit           editor object
 292   * @param filename_vpath file name
 293   * @param st             buffer for store stat info
 294   * @return TRUE for success, FALSE for error.
 295   */
 296 
 297 static gboolean
 298 check_file_access (WEdit * edit, const vfs_path_t * filename_vpath, struct stat *st)
     /* [previous][next][first][last][top][bottom][index][help]  */
 299 {
 300     static uintmax_t threshold = UINTMAX_MAX;
 301     int file;
 302     gchar *errmsg = NULL;
 303     gboolean ret = TRUE;
 304 
 305     /* Try opening an existing file */
 306     file = mc_open (filename_vpath, O_NONBLOCK | O_RDONLY | O_BINARY, 0666);
 307     if (file < 0)
 308     {
 309         /*
 310          * Try creating the file. O_EXCL prevents following broken links
 311          * and opening existing files.
 312          */
 313         file = mc_open (filename_vpath, O_NONBLOCK | O_RDONLY | O_BINARY | O_CREAT | O_EXCL, 0666);
 314         if (file < 0)
 315         {
 316             errmsg =
 317                 g_strdup_printf (_("Cannot open %s for reading"), vfs_path_as_str (filename_vpath));
 318             goto cleanup;
 319         }
 320 
 321         /* New file, delete it if it's not modified or saved */
 322         edit->delete_file = 1;
 323     }
 324 
 325     /* Check what we have opened */
 326     if (mc_fstat (file, st) < 0)
 327     {
 328         errmsg =
 329             g_strdup_printf (_("Cannot get size/permissions for %s"),
 330                              vfs_path_as_str (filename_vpath));
 331         goto cleanup;
 332     }
 333 
 334     /* We want to open regular files only */
 335     if (!S_ISREG (st->st_mode))
 336     {
 337         errmsg =
 338             g_strdup_printf (_("\"%s\" is not a regular file"), vfs_path_as_str (filename_vpath));
 339         goto cleanup;
 340     }
 341 
 342     /* get file size threshold for alarm */
 343     if (threshold == UINTMAX_MAX)
 344     {
 345         gboolean err = FALSE;
 346 
 347         threshold = parse_integer (option_filesize_threshold, &err);
 348         if (err)
 349             threshold = option_filesize_default_threshold;
 350     }
 351 
 352     /*
 353      * Don't delete non-empty files.
 354      * O_EXCL should prevent it, but let's be on the safe side.
 355      */
 356     if (st->st_size > 0)
 357         edit->delete_file = 0;
 358 
 359     if ((uintmax_t) st->st_size > threshold)
 360     {
 361         int act;
 362 
 363         errmsg = g_strdup_printf (_("File \"%s\" is too large.\nOpen it anyway?"),
 364                                   vfs_path_as_str (filename_vpath));
 365         act = edit_query_dialog2 (_("Warning"), errmsg, _("&Yes"), _("&No"));
 366         MC_PTR_FREE (errmsg);
 367 
 368         if (act != 0)
 369             ret = FALSE;
 370     }
 371 
 372   cleanup:
 373     (void) mc_close (file);
 374 
 375     if (errmsg != NULL)
 376     {
 377         edit_error_dialog (_("Error"), errmsg);
 378         g_free (errmsg);
 379         ret = FALSE;
 380     }
 381 
 382     return ret;
 383 }
 384 
 385 /* --------------------------------------------------------------------------------------------- */
 386 
 387 /**
 388  * Open the file and load it into the buffers, either directly or using
 389  * a filter.  Return TRUE on success, FALSE on error.
 390  *
 391  * Fast loading (edit_load_file_fast) is used when the file size is
 392  * known.  In this case the data is read into the buffers by blocks.
 393  * If the file size is not known, the data is loaded byte by byte in
 394  * edit_insert_file.
 395  *
 396  * @param edit editor object
 397  * @return TRUE if file was successfully opened and loaded to buffers, FALSE otherwise
 398  */
 399 static gboolean
 400 edit_load_file (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 401 {
 402     gboolean fast_load = TRUE;
 403 
 404     /* Cannot do fast load if a filter is used */
 405     if (edit_find_filter (edit->filename_vpath) >= 0)
 406         fast_load = FALSE;
 407 
 408     /*
 409      * FIXME: line end translation should disable fast loading as well
 410      * Consider doing fseek() to the end and ftell() for the real size.
 411      */
 412     if (edit->filename_vpath != NULL)
 413     {
 414         /*
 415          * VFS may report file size incorrectly, and slow load is not a big
 416          * deal considering overhead in VFS.
 417          */
 418         if (!vfs_file_is_local (edit->filename_vpath))
 419             fast_load = FALSE;
 420 
 421         /* If we are dealing with a real file, check that it exists */
 422         if (!check_file_access (edit, edit->filename_vpath, &edit->stat1))
 423         {
 424             edit_clean (edit);
 425             return FALSE;
 426         }
 427     }
 428     else
 429     {
 430         /* nothing to load */
 431         fast_load = FALSE;
 432     }
 433 
 434     if (fast_load)
 435     {
 436         edit_buffer_init (&edit->buffer, edit->stat1.st_size);
 437 
 438         if (!edit_load_file_fast (&edit->buffer, edit->filename_vpath))
 439         {
 440             edit_clean (edit);
 441             return FALSE;
 442         }
 443     }
 444     else
 445     {
 446         edit_buffer_init (&edit->buffer, 0);
 447 
 448         if (edit->filename_vpath != NULL
 449             && *(vfs_path_get_by_index (edit->filename_vpath, 0)->path) != '\0')
 450         {
 451             edit->undo_stack_disable = 1;
 452             if (edit_insert_file (edit, edit->filename_vpath) < 0)
 453             {
 454                 edit_clean (edit);
 455                 return FALSE;
 456             }
 457             edit->undo_stack_disable = 0;
 458         }
 459     }
 460     edit->lb = LB_ASIS;
 461     return TRUE;
 462 }
 463 
 464 /* --------------------------------------------------------------------------------------------- */
 465 /**
 466  * Restore saved cursor position and/or bookmarks in the file
 467  *
 468  * @param edit editor object
 469  * @param load_position If TRUE, load bookmarks and cursor position and aply them.
 470  *                      If FALSE, load bookmarks only.
 471  */
 472 
 473 static void
 474 edit_load_position (WEdit * edit, gboolean load_position)
     /* [previous][next][first][last][top][bottom][index][help]  */
 475 {
 476     long line, column;
 477     off_t offset;
 478 
 479     if (edit->filename_vpath == NULL
 480         || *(vfs_path_get_by_index (edit->filename_vpath, 0)->path) == '\0')
 481         return;
 482 
 483     load_file_position (edit->filename_vpath, &line, &column, &offset, &edit->serialized_bookmarks);
 484     /* apply bookmarks in any case */
 485     book_mark_restore (edit, BOOK_MARK_COLOR);
 486 
 487     if (!load_position)
 488         return;
 489 
 490     if (line > 0)
 491     {
 492         edit_move_to_line (edit, line - 1);
 493         edit->prev_col = column;
 494     }
 495     else if (offset > 0)
 496     {
 497         edit_cursor_move (edit, offset);
 498         line = edit->buffer.curs_line;
 499         edit->search_start = edit->buffer.curs1;
 500     }
 501 
 502     edit_move_to_prev_col (edit, edit_buffer_get_current_bol (&edit->buffer));
 503     edit_move_display (edit, line - (WIDGET (edit)->rect.lines / 2));
 504 }
 505 
 506 /* --------------------------------------------------------------------------------------------- */
 507 /** Save cursor position in the file */
 508 
 509 static void
 510 edit_save_position (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 511 {
 512     if (edit->filename_vpath == NULL
 513         || *(vfs_path_get_by_index (edit->filename_vpath, 0)->path) == '\0')
 514         return;
 515 
 516     book_mark_serialize (edit, BOOK_MARK_COLOR);
 517     save_file_position (edit->filename_vpath, edit->buffer.curs_line + 1, edit->curs_col,
 518                         edit->buffer.curs1, edit->serialized_bookmarks);
 519     edit->serialized_bookmarks = NULL;
 520 }
 521 
 522 /* --------------------------------------------------------------------------------------------- */
 523 /** Clean the WEdit stricture except the widget part */
 524 
 525 static void
 526 edit_purge_widget (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 527 {
 528     size_t len = sizeof (WEdit) - sizeof (Widget);
 529     char *start = (char *) edit + sizeof (Widget);
 530     memset (start, 0, len);
 531 }
 532 
 533 /* --------------------------------------------------------------------------------------------- */
 534 
 535 /*
 536    TODO: if the user undos until the stack bottom, and the stack has not wrapped,
 537    then the file should be as it was when he loaded up. Then set edit->modified to 0.
 538  */
 539 
 540 static long
 541 edit_pop_undo_action (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 542 {
 543     long c;
 544     unsigned long sp = edit->undo_stack_pointer;
 545 
 546     if (sp == edit->undo_stack_bottom)
 547         return STACK_BOTTOM;
 548 
 549     sp = (sp - 1) & edit->undo_stack_size_mask;
 550     c = edit->undo_stack[sp];
 551     if (c >= 0)
 552     {
 553         /*      edit->undo_stack[sp] = '@'; */
 554         edit->undo_stack_pointer = (edit->undo_stack_pointer - 1) & edit->undo_stack_size_mask;
 555         return c;
 556     }
 557 
 558     if (sp == edit->undo_stack_bottom)
 559         return STACK_BOTTOM;
 560 
 561     c = edit->undo_stack[(sp - 1) & edit->undo_stack_size_mask];
 562     if (edit->undo_stack[sp] == -2)
 563     {
 564         /*      edit->undo_stack[sp] = '@'; */
 565         edit->undo_stack_pointer = sp;
 566     }
 567     else
 568         edit->undo_stack[sp]++;
 569 
 570     return c;
 571 }
 572 
 573 static long
 574 edit_pop_redo_action (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 575 {
 576     long c;
 577     unsigned long sp = edit->redo_stack_pointer;
 578 
 579     if (sp == edit->redo_stack_bottom)
 580         return STACK_BOTTOM;
 581 
 582     sp = (sp - 1) & edit->redo_stack_size_mask;
 583     c = edit->redo_stack[sp];
 584     if (c >= 0)
 585     {
 586         edit->redo_stack_pointer = (edit->redo_stack_pointer - 1) & edit->redo_stack_size_mask;
 587         return c;
 588     }
 589 
 590     if (sp == edit->redo_stack_bottom)
 591         return STACK_BOTTOM;
 592 
 593     c = edit->redo_stack[(sp - 1) & edit->redo_stack_size_mask];
 594     if (edit->redo_stack[sp] == -2)
 595         edit->redo_stack_pointer = sp;
 596     else
 597         edit->redo_stack[sp]++;
 598 
 599     return c;
 600 }
 601 
 602 static long
 603 get_prev_undo_action (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 604 {
 605     long c;
 606     unsigned long sp = edit->undo_stack_pointer;
 607 
 608     if (sp == edit->undo_stack_bottom)
 609         return STACK_BOTTOM;
 610 
 611     sp = (sp - 1) & edit->undo_stack_size_mask;
 612     c = edit->undo_stack[sp];
 613     if (c >= 0)
 614         return c;
 615 
 616     if (sp == edit->undo_stack_bottom)
 617         return STACK_BOTTOM;
 618 
 619     c = edit->undo_stack[(sp - 1) & edit->undo_stack_size_mask];
 620     return c;
 621 }
 622 
 623 /* --------------------------------------------------------------------------------------------- */
 624 /** is called whenever a modification is made by one of the four routines below */
 625 
 626 static void
 627 edit_modification (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 628 {
 629     edit->caches_valid = FALSE;
 630 
 631     /* raise lock when file modified */
 632     if (!edit->modified && !edit->delete_file)
 633         edit->locked = lock_file (edit->filename_vpath);
 634     edit->modified = 1;
 635 }
 636 
 637 /* --------------------------------------------------------------------------------------------- */
 638 /* high level cursor movement commands */
 639 /* --------------------------------------------------------------------------------------------- */
 640 /** check whether cursor is in indent part of line
 641  *
 642  * @param edit editor object
 643  *
 644  * @return TRUE if cursor is in indent, FALSE otherwise
 645  */
 646 
 647 static gboolean
 648 is_in_indent (const edit_buffer_t * buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 649 {
 650     off_t p;
 651 
 652     for (p = edit_buffer_get_current_bol (buf); p < buf->curs1; p++)
 653         if (strchr (" \t", edit_buffer_get_byte (buf, p)) == NULL)
 654             return FALSE;
 655 
 656     return TRUE;
 657 }
 658 
 659 /* --------------------------------------------------------------------------------------------- */
 660 /** check whether line in editor is blank or not
 661  *
 662  * @param edit editor object
 663  * @param offset position in file
 664  *
 665  * @return TRUE if line in blank, FALSE otherwise
 666  */
 667 
 668 static gboolean
 669 is_blank (const edit_buffer_t * buf, off_t offset)
     /* [previous][next][first][last][top][bottom][index][help]  */
 670 {
 671     off_t s, f;
 672 
 673     s = edit_buffer_get_bol (buf, offset);
 674     f = edit_buffer_get_eol (buf, offset) - 1;
 675     while (s <= f)
 676     {
 677         int c;
 678 
 679         c = edit_buffer_get_byte (buf, s++);
 680         if (!isspace (c))
 681             return FALSE;
 682     }
 683     return TRUE;
 684 }
 685 
 686 /* --------------------------------------------------------------------------------------------- */
 687 /** returns the offset of line i */
 688 
 689 static off_t
 690 edit_find_line (WEdit * edit, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 691 {
 692     long i, j = 0;
 693     long m = 2000000000;        /* what is the magic number? */
 694 
 695     if (!edit->caches_valid)
 696     {
 697         memset (edit->line_numbers, 0, sizeof (edit->line_numbers));
 698         memset (edit->line_offsets, 0, sizeof (edit->line_offsets));
 699         /* three offsets that we *know* are line 0 at 0 and these two: */
 700         edit->line_numbers[1] = edit->buffer.curs_line;
 701         edit->line_offsets[1] = edit_buffer_get_current_bol (&edit->buffer);
 702         edit->line_numbers[2] = edit->buffer.lines;
 703         edit->line_offsets[2] = edit_buffer_get_bol (&edit->buffer, edit->buffer.size);
 704         edit->caches_valid = TRUE;
 705     }
 706     if (line >= edit->buffer.lines)
 707         return edit->line_offsets[2];
 708     if (line <= 0)
 709         return 0;
 710     /* find the closest known point */
 711     for (i = 0; i < N_LINE_CACHES; i++)
 712     {
 713         long n;
 714 
 715         n = labs (edit->line_numbers[i] - line);
 716         if (n < m)
 717         {
 718             m = n;
 719             j = i;
 720         }
 721     }
 722     if (m == 0)
 723         return edit->line_offsets[j];   /* know the offset exactly */
 724     if (m == 1 && j >= 3)
 725         i = j;                  /* one line different - caller might be looping, so stay in this cache */
 726     else
 727         i = 3 + (rand () % (N_LINE_CACHES - 3));
 728     if (line > edit->line_numbers[j])
 729         edit->line_offsets[i] =
 730             edit_buffer_get_forward_offset (&edit->buffer, edit->line_offsets[j],
 731                                             line - edit->line_numbers[j], 0);
 732     else
 733         edit->line_offsets[i] =
 734             edit_buffer_get_backward_offset (&edit->buffer, edit->line_offsets[j],
 735                                              edit->line_numbers[j] - line);
 736     edit->line_numbers[i] = line;
 737     return edit->line_offsets[i];
 738 }
 739 
 740 /* --------------------------------------------------------------------------------------------- */
 741 /** moves up until a blank line is reached, or until just
 742    before a non-blank line is reached */
 743 
 744 static void
 745 edit_move_up_paragraph (WEdit * edit, gboolean do_scroll)
     /* [previous][next][first][last][top][bottom][index][help]  */
 746 {
 747     long i = 0;
 748 
 749     if (edit->buffer.curs_line > 1)
 750     {
 751         if (!edit_line_is_blank (edit, edit->buffer.curs_line))
 752         {
 753             for (i = edit->buffer.curs_line - 1; i != 0; i--)
 754                 if (edit_line_is_blank (edit, i))
 755                     break;
 756         }
 757         else if (edit_line_is_blank (edit, edit->buffer.curs_line - 1))
 758         {
 759             for (i = edit->buffer.curs_line - 1; i != 0; i--)
 760                 if (!edit_line_is_blank (edit, i))
 761                 {
 762                     i++;
 763                     break;
 764                 }
 765         }
 766         else
 767         {
 768             for (i = edit->buffer.curs_line - 1; i != 0; i--)
 769                 if (edit_line_is_blank (edit, i))
 770                     break;
 771         }
 772     }
 773 
 774     edit_move_up (edit, edit->buffer.curs_line - i, do_scroll);
 775 }
 776 
 777 /* --------------------------------------------------------------------------------------------- */
 778 /** moves down until a blank line is reached, or until just
 779    before a non-blank line is reached */
 780 
 781 static void
 782 edit_move_down_paragraph (WEdit * edit, gboolean do_scroll)
     /* [previous][next][first][last][top][bottom][index][help]  */
 783 {
 784     long i;
 785 
 786     if (edit->buffer.curs_line >= edit->buffer.lines - 1)
 787         i = edit->buffer.lines;
 788     else if (!edit_line_is_blank (edit, edit->buffer.curs_line))
 789     {
 790         for (i = edit->buffer.curs_line + 1; i != 0; i++)
 791             if (edit_line_is_blank (edit, i) || i >= edit->buffer.lines)
 792                 break;
 793     }
 794     else if (edit_line_is_blank (edit, edit->buffer.curs_line + 1))
 795     {
 796         for (i = edit->buffer.curs_line + 1; i != 0; i++)
 797             if (!edit_line_is_blank (edit, i) || i > edit->buffer.lines)
 798             {
 799                 i--;
 800                 break;
 801             }
 802     }
 803     else
 804     {
 805         for (i = edit->buffer.curs_line + 1; i != 0; i++)
 806             if (edit_line_is_blank (edit, i) || i >= edit->buffer.lines)
 807                 break;
 808     }
 809     edit_move_down (edit, i - edit->buffer.curs_line, do_scroll);
 810 }
 811 
 812 /* --------------------------------------------------------------------------------------------- */
 813 
 814 static void
 815 edit_begin_page (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 816 {
 817     edit_update_curs_row (edit);
 818     edit_move_up (edit, edit->curs_row, FALSE);
 819 }
 820 
 821 /* --------------------------------------------------------------------------------------------- */
 822 
 823 static void
 824 edit_end_page (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 825 {
 826     edit_update_curs_row (edit);
 827     edit_move_down (edit, WIDGET (edit)->rect.lines - edit->curs_row - 1, FALSE);
 828 }
 829 
 830 
 831 /* --------------------------------------------------------------------------------------------- */
 832 /** goto beginning of text */
 833 
 834 static void
 835 edit_move_to_top (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 836 {
 837     if (edit->buffer.curs_line != 0)
 838     {
 839         edit_cursor_move (edit, -edit->buffer.curs1);
 840         edit_move_to_prev_col (edit, 0);
 841         edit->force |= REDRAW_PAGE;
 842         edit->search_start = 0;
 843         edit_update_curs_row (edit);
 844     }
 845 }
 846 
 847 /* --------------------------------------------------------------------------------------------- */
 848 /** goto end of text */
 849 
 850 static void
 851 edit_move_to_bottom (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 852 {
 853     if (edit->buffer.curs_line < edit->buffer.lines)
 854     {
 855         edit_move_down (edit, edit->buffer.lines - edit->curs_row, FALSE);
 856         edit->start_display = edit->buffer.size;
 857         edit->start_line = edit->buffer.lines;
 858         edit_scroll_upward (edit, WIDGET (edit)->rect.lines - 1);
 859         edit->force |= REDRAW_PAGE;
 860     }
 861 }
 862 
 863 /* --------------------------------------------------------------------------------------------- */
 864 /** goto beginning of line */
 865 
 866 static void
 867 edit_cursor_to_bol (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 868 {
 869     edit_cursor_move (edit, edit_buffer_get_current_bol (&edit->buffer) - edit->buffer.curs1);
 870     edit->search_start = edit->buffer.curs1;
 871     edit->prev_col = edit_get_col (edit);
 872     edit->over_col = 0;
 873 }
 874 
 875 /* --------------------------------------------------------------------------------------------- */
 876 /** goto end of line */
 877 
 878 static void
 879 edit_cursor_to_eol (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 880 {
 881     edit_cursor_move (edit, edit_buffer_get_current_eol (&edit->buffer) - edit->buffer.curs1);
 882     edit->search_start = edit->buffer.curs1;
 883     edit->prev_col = edit_get_col (edit);
 884     edit->over_col = 0;
 885 }
 886 
 887 /* --------------------------------------------------------------------------------------------- */
 888 
 889 static unsigned long
 890 my_type_of (int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
 891 {
 892     unsigned long x, r = 0;
 893     const char *p, *q;
 894     const char option_chars_move_whole_word[] =
 895         "!=&|<>^~ !:;, !'!`!.?!\"!( !) !{ !} !Aa0 !+-*/= |<> ![ !] !\\#! ";
 896 
 897     if (c == 0)
 898         return 0;
 899     if (c == '!')
 900         return 2;
 901 
 902     if (g_ascii_isupper ((gchar) c))
 903         c = 'A';
 904     else if (g_ascii_islower ((gchar) c))
 905         c = 'a';
 906     else if (g_ascii_isalpha (c))
 907         c = 'a';
 908     else if (isdigit (c))
 909         c = '0';
 910     else if (isspace (c))
 911         c = ' ';
 912     q = strchr (option_chars_move_whole_word, c);
 913     if (!q)
 914         return 0xFFFFFFFFUL;
 915     do
 916     {
 917         for (x = 1, p = option_chars_move_whole_word; p < q; p++)
 918             if (*p == '!')
 919                 x <<= 1;
 920         r |= x;
 921     }
 922     while ((q = strchr (q + 1, c)));
 923     return r;
 924 }
 925 
 926 /* --------------------------------------------------------------------------------------------- */
 927 
 928 static void
 929 edit_left_word_move (WEdit * edit, int s)
     /* [previous][next][first][last][top][bottom][index][help]  */
 930 {
 931     while (TRUE)
 932     {
 933         int c1, c2;
 934 
 935         if (edit->column_highlight
 936             && edit->mark1 != edit->mark2
 937             && edit->over_col == 0
 938             && edit->buffer.curs1 == edit_buffer_get_current_bol (&edit->buffer))
 939             break;
 940         edit_cursor_move (edit, -1);
 941         if (edit->buffer.curs1 == 0)
 942             break;
 943         c1 = edit_buffer_get_previous_byte (&edit->buffer);
 944         c2 = edit_buffer_get_current_byte (&edit->buffer);
 945         if (c1 == '\n' || c2 == '\n')
 946             break;
 947         if ((my_type_of (c1) & my_type_of (c2)) == 0)
 948             break;
 949         if (isspace (c1) && !isspace (c2))
 950             break;
 951         if (s != 0 && !isspace (c1) && isspace (c2))
 952             break;
 953     }
 954 }
 955 
 956 /* --------------------------------------------------------------------------------------------- */
 957 
 958 static void
 959 edit_left_word_move_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 960 {
 961     edit_left_word_move (edit, 0);
 962     edit->force |= REDRAW_PAGE;
 963 }
 964 
 965 /* --------------------------------------------------------------------------------------------- */
 966 
 967 static void
 968 edit_right_word_move (WEdit * edit, int s)
     /* [previous][next][first][last][top][bottom][index][help]  */
 969 {
 970     while (TRUE)
 971     {
 972         int c1, c2;
 973 
 974         if (edit->column_highlight
 975             && edit->mark1 != edit->mark2
 976             && edit->over_col == 0
 977             && edit->buffer.curs1 == edit_buffer_get_current_eol (&edit->buffer))
 978             break;
 979         edit_cursor_move (edit, 1);
 980         if (edit->buffer.curs1 >= edit->buffer.size)
 981             break;
 982         c1 = edit_buffer_get_previous_byte (&edit->buffer);
 983         c2 = edit_buffer_get_current_byte (&edit->buffer);
 984         if (c1 == '\n' || c2 == '\n')
 985             break;
 986         if ((my_type_of (c1) & my_type_of (c2)) == 0)
 987             break;
 988         if (isspace (c1) && !isspace (c2))
 989             break;
 990         if (s != 0 && !isspace (c1) && isspace (c2))
 991             break;
 992     }
 993 }
 994 
 995 /* --------------------------------------------------------------------------------------------- */
 996 
 997 static void
 998 edit_right_word_move_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 999 {
1000     edit_right_word_move (edit, 0);
1001     edit->force |= REDRAW_PAGE;
1002 }
1003 
1004 /* --------------------------------------------------------------------------------------------- */
1005 
1006 static void
1007 edit_right_char_move_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1008 {
1009     int char_length = 1;
1010     int c;
1011 
1012 #ifdef HAVE_CHARSET
1013     if (edit->utf8)
1014     {
1015         c = edit_buffer_get_utf (&edit->buffer, edit->buffer.curs1, &char_length);
1016         if (char_length < 1)
1017             char_length = 1;
1018     }
1019     else
1020 #endif
1021         c = edit_buffer_get_current_byte (&edit->buffer);
1022 
1023     if (option_cursor_beyond_eol && c == '\n')
1024         edit->over_col++;
1025     else
1026         edit_cursor_move (edit, char_length);
1027 }
1028 
1029 /* --------------------------------------------------------------------------------------------- */
1030 
1031 static void
1032 edit_left_char_move_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1033 {
1034     int char_length = 1;
1035 
1036     if (edit->column_highlight
1037         && option_cursor_beyond_eol
1038         && edit->mark1 != edit->mark2
1039         && edit->over_col == 0 && edit->buffer.curs1 == edit_buffer_get_current_bol (&edit->buffer))
1040         return;
1041 #ifdef HAVE_CHARSET
1042     if (edit->utf8)
1043     {
1044         edit_buffer_get_prev_utf (&edit->buffer, edit->buffer.curs1, &char_length);
1045         if (char_length < 1)
1046             char_length = 1;
1047     }
1048 #endif
1049 
1050     if (option_cursor_beyond_eol && edit->over_col > 0)
1051         edit->over_col--;
1052     else
1053         edit_cursor_move (edit, -char_length);
1054 }
1055 
1056 /* --------------------------------------------------------------------------------------------- */
1057 /** Up or down cursor moving.
1058  direction = TRUE - move up
1059            = FALSE - move down
1060 */
1061 
1062 static void
1063 edit_move_updown (WEdit * edit, long lines, gboolean do_scroll, gboolean direction)
     /* [previous][next][first][last][top][bottom][index][help]  */
1064 {
1065     long p;
1066     long l = direction ? edit->buffer.curs_line : edit->buffer.lines - edit->buffer.curs_line;
1067 
1068     if (lines > l)
1069         lines = l;
1070 
1071     if (lines == 0)
1072         return;
1073 
1074     if (lines > 1)
1075         edit->force |= REDRAW_PAGE;
1076     if (do_scroll)
1077     {
1078         if (direction)
1079             edit_scroll_upward (edit, lines);
1080         else
1081             edit_scroll_downward (edit, lines);
1082     }
1083     p = edit_buffer_get_current_bol (&edit->buffer);
1084     p = direction ? edit_buffer_get_backward_offset (&edit->buffer, p, lines) :
1085         edit_buffer_get_forward_offset (&edit->buffer, p, lines, 0);
1086     edit_cursor_move (edit, p - edit->buffer.curs1);
1087     edit_move_to_prev_col (edit, p);
1088 
1089 #ifdef HAVE_CHARSET
1090     /* search start of current multibyte char (like CJK) */
1091     if (edit->buffer.curs1 > 0 && edit->buffer.curs1 + 1 < edit->buffer.size
1092         && edit_buffer_get_current_byte (&edit->buffer) >= 256)
1093     {
1094         edit_right_char_move_cmd (edit);
1095         edit_left_char_move_cmd (edit);
1096     }
1097 #endif
1098 
1099     edit->search_start = edit->buffer.curs1;
1100     edit->found_len = 0;
1101 }
1102 
1103 /* --------------------------------------------------------------------------------------------- */
1104 
1105 static void
1106 edit_right_delete_word (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1107 {
1108     while (edit->buffer.curs1 < edit->buffer.size)
1109     {
1110         int c1, c2;
1111 
1112         c1 = edit_delete (edit, TRUE);
1113         c2 = edit_buffer_get_current_byte (&edit->buffer);
1114         if (c1 == '\n' || c2 == '\n')
1115             break;
1116         if ((isspace (c1) == 0) != (isspace (c2) == 0))
1117             break;
1118         if ((my_type_of (c1) & my_type_of (c2)) == 0)
1119             break;
1120     }
1121 }
1122 
1123 /* --------------------------------------------------------------------------------------------- */
1124 
1125 static void
1126 edit_left_delete_word (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1127 {
1128     while (edit->buffer.curs1 > 0)
1129     {
1130         int c1, c2;
1131 
1132         c1 = edit_backspace (edit, TRUE);
1133         c2 = edit_buffer_get_previous_byte (&edit->buffer);
1134         if (c1 == '\n' || c2 == '\n')
1135             break;
1136         if ((isspace (c1) == 0) != (isspace (c2) == 0))
1137             break;
1138         if ((my_type_of (c1) & my_type_of (c2)) == 0)
1139             break;
1140     }
1141 }
1142 
1143 /* --------------------------------------------------------------------------------------------- */
1144 /**
1145    the start column position is not recorded, and hence does not
1146    undo as it happed. But who would notice.
1147  */
1148 
1149 static void
1150 edit_do_undo (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1151 {
1152     long ac;
1153     long count = 0;
1154 
1155     edit->undo_stack_disable = 1;       /* don't record undo's onto undo stack! */
1156     edit->over_col = 0;
1157     while ((ac = edit_pop_undo_action (edit)) < KEY_PRESS)
1158     {
1159         switch ((int) ac)
1160         {
1161         case STACK_BOTTOM:
1162             goto done_undo;
1163         case CURS_RIGHT:
1164             edit_cursor_move (edit, 1);
1165             break;
1166         case CURS_LEFT:
1167             edit_cursor_move (edit, -1);
1168             break;
1169         case BACKSPACE:
1170         case BACKSPACE_BR:
1171             edit_backspace (edit, TRUE);
1172             break;
1173         case DELCHAR:
1174         case DELCHAR_BR:
1175             edit_delete (edit, TRUE);
1176             break;
1177         case COLUMN_ON:
1178             edit->column_highlight = 1;
1179             break;
1180         case COLUMN_OFF:
1181             edit->column_highlight = 0;
1182             break;
1183         default:
1184             break;
1185         }
1186         if (ac >= 256 && ac < 512)
1187             edit_insert_ahead (edit, ac - 256);
1188         if (ac >= 0 && ac < 256)
1189             edit_insert (edit, ac);
1190 
1191         if (ac >= MARK_1 - 2 && ac < MARK_2 - 2)
1192         {
1193             edit->mark1 = ac - MARK_1;
1194             edit->column1 =
1195                 (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, edit->mark1),
1196                                            0, edit->mark1);
1197         }
1198         if (ac >= MARK_2 - 2 && ac < MARK_CURS - 2)
1199         {
1200             edit->mark2 = ac - MARK_2;
1201             edit->column2 =
1202                 (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, edit->mark2),
1203                                            0, edit->mark2);
1204         }
1205         else if (ac >= MARK_CURS - 2 && ac < KEY_PRESS)
1206         {
1207             edit->end_mark_curs = ac - MARK_CURS;
1208         }
1209         if (count++)
1210             edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
1211     }
1212 
1213     if (edit->start_display > ac - KEY_PRESS)
1214     {
1215         edit->start_line -=
1216             edit_buffer_count_lines (&edit->buffer, ac - KEY_PRESS, edit->start_display);
1217         edit->force |= REDRAW_PAGE;
1218     }
1219     else if (edit->start_display < ac - KEY_PRESS)
1220     {
1221         edit->start_line +=
1222             edit_buffer_count_lines (&edit->buffer, edit->start_display, ac - KEY_PRESS);
1223         edit->force |= REDRAW_PAGE;
1224     }
1225     edit->start_display = ac - KEY_PRESS;       /* see push and pop above */
1226     edit_update_curs_row (edit);
1227 
1228   done_undo:
1229     edit->undo_stack_disable = 0;
1230 }
1231 
1232 /* --------------------------------------------------------------------------------------------- */
1233 
1234 static void
1235 edit_do_redo (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1236 {
1237     long ac;
1238     long count = 0;
1239 
1240     if (edit->redo_stack_reset)
1241         return;
1242 
1243     edit->over_col = 0;
1244     while ((ac = edit_pop_redo_action (edit)) < KEY_PRESS)
1245     {
1246         switch ((int) ac)
1247         {
1248         case STACK_BOTTOM:
1249             goto done_redo;
1250         case CURS_RIGHT:
1251             edit_cursor_move (edit, 1);
1252             break;
1253         case CURS_LEFT:
1254             edit_cursor_move (edit, -1);
1255             break;
1256         case BACKSPACE:
1257             edit_backspace (edit, TRUE);
1258             break;
1259         case DELCHAR:
1260             edit_delete (edit, TRUE);
1261             break;
1262         case COLUMN_ON:
1263             edit->column_highlight = 1;
1264             break;
1265         case COLUMN_OFF:
1266             edit->column_highlight = 0;
1267             break;
1268         default:
1269             break;
1270         }
1271         if (ac >= 256 && ac < 512)
1272             edit_insert_ahead (edit, ac - 256);
1273         if (ac >= 0 && ac < 256)
1274             edit_insert (edit, ac);
1275 
1276         if (ac >= MARK_1 - 2 && ac < MARK_2 - 2)
1277         {
1278             edit->mark1 = ac - MARK_1;
1279             edit->column1 =
1280                 (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, edit->mark1),
1281                                            0, edit->mark1);
1282         }
1283         else if (ac >= MARK_2 - 2 && ac < KEY_PRESS)
1284         {
1285             edit->mark2 = ac - MARK_2;
1286             edit->column2 =
1287                 (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, edit->mark2),
1288                                            0, edit->mark2);
1289         }
1290         /* more than one pop usually means something big */
1291         if (count++)
1292             edit->force |= REDRAW_PAGE;
1293     }
1294 
1295     if (edit->start_display > ac - KEY_PRESS)
1296     {
1297         edit->start_line -=
1298             edit_buffer_count_lines (&edit->buffer, ac - KEY_PRESS, edit->start_display);
1299         edit->force |= REDRAW_PAGE;
1300     }
1301     else if (edit->start_display < ac - KEY_PRESS)
1302     {
1303         edit->start_line +=
1304             edit_buffer_count_lines (&edit->buffer, edit->start_display, ac - KEY_PRESS);
1305         edit->force |= REDRAW_PAGE;
1306     }
1307     edit->start_display = ac - KEY_PRESS;       /* see push and pop above */
1308     edit_update_curs_row (edit);
1309 
1310   done_redo:
1311     ;
1312 }
1313 
1314 /* --------------------------------------------------------------------------------------------- */
1315 
1316 static void
1317 edit_group_undo (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1318 {
1319     long ac = KEY_PRESS;
1320     long cur_ac = KEY_PRESS;
1321     while (ac != STACK_BOTTOM && ac == cur_ac)
1322     {
1323         cur_ac = get_prev_undo_action (edit);
1324         edit_do_undo (edit);
1325         ac = get_prev_undo_action (edit);
1326         /* exit from cycle if option_group_undo is not set,
1327          * and make single UNDO operation
1328          */
1329         if (!option_group_undo)
1330             ac = STACK_BOTTOM;
1331     }
1332 }
1333 
1334 /* --------------------------------------------------------------------------------------------- */
1335 
1336 static void
1337 edit_delete_to_line_end (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1338 {
1339     while (edit_buffer_get_current_byte (&edit->buffer) != '\n' && edit->buffer.curs2 != 0)
1340         edit_delete (edit, TRUE);
1341 }
1342 
1343 /* --------------------------------------------------------------------------------------------- */
1344 
1345 static void
1346 edit_delete_to_line_begin (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1347 {
1348     while (edit_buffer_get_previous_byte (&edit->buffer) != '\n' && edit->buffer.curs1 != 0)
1349         edit_backspace (edit, TRUE);
1350 }
1351 
1352 /* --------------------------------------------------------------------------------------------- */
1353 
1354 static gboolean
1355 is_aligned_on_a_tab (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1356 {
1357     long curs_col;
1358 
1359     edit_update_curs_col (edit);
1360     curs_col = edit->curs_col % (TAB_SIZE * space_width);
1361     return (curs_col == 0 || curs_col == (HALF_TAB_SIZE * space_width));
1362 }
1363 
1364 /* --------------------------------------------------------------------------------------------- */
1365 
1366 static gboolean
1367 right_of_four_spaces (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1368 {
1369     int i, ch = 0;
1370 
1371     for (i = 1; i <= HALF_TAB_SIZE; i++)
1372         ch |= edit_buffer_get_byte (&edit->buffer, edit->buffer.curs1 - i);
1373 
1374     return (ch == ' ' && is_aligned_on_a_tab (edit));
1375 }
1376 
1377 /* --------------------------------------------------------------------------------------------- */
1378 
1379 static gboolean
1380 left_of_four_spaces (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1381 {
1382     int i, ch = 0;
1383 
1384     for (i = 0; i < HALF_TAB_SIZE; i++)
1385         ch |= edit_buffer_get_byte (&edit->buffer, edit->buffer.curs1 + i);
1386 
1387     return (ch == ' ' && is_aligned_on_a_tab (edit));
1388 }
1389 
1390 /* --------------------------------------------------------------------------------------------- */
1391 
1392 static void
1393 edit_auto_indent (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1394 {
1395     off_t p;
1396 
1397     p = edit->buffer.curs1;
1398     /* use the previous line as a template */
1399     p = edit_buffer_get_backward_offset (&edit->buffer, p, 1);
1400     /* copy the leading whitespace of the line */
1401     while (TRUE)
1402     {                           /* no range check - the line _is_ \n-terminated */
1403         char c;
1404 
1405         c = edit_buffer_get_byte (&edit->buffer, p++);
1406         if (!whitespace (c))
1407             break;
1408         edit_insert (edit, c);
1409     }
1410 }
1411 
1412 /* --------------------------------------------------------------------------------------------- */
1413 
1414 static inline void
1415 edit_double_newline (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1416 {
1417     edit_insert (edit, '\n');
1418     if (edit_buffer_get_current_byte (&edit->buffer) == '\n'
1419         || edit_buffer_get_byte (&edit->buffer, edit->buffer.curs1 - 2) == '\n')
1420         return;
1421     edit->force |= REDRAW_PAGE;
1422     edit_insert (edit, '\n');
1423 }
1424 
1425 /* --------------------------------------------------------------------------------------------- */
1426 
1427 static void
1428 insert_spaces_tab (WEdit * edit, gboolean half)
     /* [previous][next][first][last][top][bottom][index][help]  */
1429 {
1430     long i;
1431 
1432     edit_update_curs_col (edit);
1433     i = option_tab_spacing * space_width;
1434     if (half)
1435         i /= 2;
1436     if (i != 0)
1437     {
1438         i = ((edit->curs_col / i) + 1) * i - edit->curs_col;
1439         while (i > 0)
1440         {
1441             edit_insert (edit, ' ');
1442             i -= space_width;
1443         }
1444     }
1445 }
1446 
1447 /* --------------------------------------------------------------------------------------------- */
1448 
1449 static inline void
1450 edit_tab_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1451 {
1452     if (option_fake_half_tabs && is_in_indent (&edit->buffer))
1453     {
1454         /* insert a half tab (usually four spaces) unless there is a
1455            half tab already behind, then delete it and insert a
1456            full tab. */
1457         if (option_fill_tabs_with_spaces || !right_of_four_spaces (edit))
1458             insert_spaces_tab (edit, TRUE);
1459         else
1460         {
1461             int i;
1462 
1463             for (i = 1; i <= HALF_TAB_SIZE; i++)
1464                 edit_backspace (edit, TRUE);
1465             edit_insert (edit, '\t');
1466         }
1467     }
1468     else if (option_fill_tabs_with_spaces)
1469         insert_spaces_tab (edit, FALSE);
1470     else
1471         edit_insert (edit, '\t');
1472 }
1473 
1474 /* --------------------------------------------------------------------------------------------- */
1475 
1476 static void
1477 check_and_wrap_line (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1478 {
1479     off_t curs;
1480 
1481     if (!option_typewriter_wrap)
1482         return;
1483     edit_update_curs_col (edit);
1484     if (edit->curs_col < option_word_wrap_line_length)
1485         return;
1486     curs = edit->buffer.curs1;
1487     while (TRUE)
1488     {
1489         int c;
1490 
1491         curs--;
1492         c = edit_buffer_get_byte (&edit->buffer, curs);
1493         if (c == '\n' || curs <= 0)
1494         {
1495             edit_insert (edit, '\n');
1496             return;
1497         }
1498         if (whitespace (c))
1499         {
1500             off_t current = edit->buffer.curs1;
1501             edit_cursor_move (edit, curs - edit->buffer.curs1 + 1);
1502             edit_insert (edit, '\n');
1503             edit_cursor_move (edit, current - edit->buffer.curs1 + 1);
1504             return;
1505         }
1506     }
1507 }
1508 
1509 /* --------------------------------------------------------------------------------------------- */
1510 /** this find the matching bracket in either direction, and sets edit->bracket
1511  *
1512  * @param edit editor object
1513  * @param in_screen seach only on the current screen
1514  * @param furthest_bracket_search count of the bytes for search
1515  *
1516  * @return position of the found bracket (-1 if no match)
1517  */
1518 
1519 static off_t
1520 edit_get_bracket (WEdit * edit, gboolean in_screen, unsigned long furthest_bracket_search)
     /* [previous][next][first][last][top][bottom][index][help]  */
1521 {
1522     const char *const b = "{}{[][()(", *p;
1523     int i = 1, inc = -1, c, d, n = 0;
1524     unsigned long j = 0;
1525     off_t q;
1526 
1527     edit_update_curs_row (edit);
1528     c = edit_buffer_get_current_byte (&edit->buffer);
1529     p = strchr (b, c);
1530     /* not on a bracket at all */
1531     if (p == NULL || *p == '\0')
1532         return -1;
1533     /* the matching bracket */
1534     d = p[1];
1535     /* going left or right? */
1536     if (strchr ("{[(", c) != NULL)
1537         inc = 1;
1538     /* no limit */
1539     if (furthest_bracket_search == 0)
1540         furthest_bracket_search--;      /* ULONG_MAX */
1541     for (q = edit->buffer.curs1 + inc;; q += inc)
1542     {
1543         int a;
1544 
1545         /* out of buffer? */
1546         if (q >= edit->buffer.size || q < 0)
1547             break;
1548         a = edit_buffer_get_byte (&edit->buffer, q);
1549         /* don't want to eat CPU */
1550         if (j++ > furthest_bracket_search)
1551             break;
1552         /* out of screen? */
1553         if (in_screen)
1554         {
1555             if (q < edit->start_display)
1556                 break;
1557             /* count lines if searching downward */
1558             if (inc > 0 && a == '\n')
1559                 if (n++ >= WIDGET (edit)->rect.lines - edit->curs_row)  /* out of screen */
1560                     break;
1561         }
1562         /* count bracket depth */
1563         i += (a == c) - (a == d);
1564         /* return if bracket depth is zero */
1565         if (i == 0)
1566             return q;
1567     }
1568     /* no match */
1569     return -1;
1570 }
1571 
1572 /* --------------------------------------------------------------------------------------------- */
1573 
1574 static inline void
1575 edit_goto_matching_bracket (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1576 {
1577     off_t q;
1578 
1579     q = edit_get_bracket (edit, 0, 0);
1580     if (q >= 0)
1581     {
1582         edit->bracket = edit->buffer.curs1;
1583         edit->force |= REDRAW_PAGE;
1584         edit_cursor_move (edit, q - edit->buffer.curs1);
1585     }
1586 }
1587 
1588 /* --------------------------------------------------------------------------------------------- */
1589 
1590 static void
1591 edit_move_block_to_right (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1592 {
1593     off_t start_mark, end_mark;
1594     long cur_bol, start_bol;
1595 
1596     if (!eval_marks (edit, &start_mark, &end_mark))
1597         return;
1598 
1599     start_bol = edit_buffer_get_bol (&edit->buffer, start_mark);
1600     cur_bol = edit_buffer_get_bol (&edit->buffer, end_mark - 1);
1601 
1602     do
1603     {
1604         edit_cursor_move (edit, cur_bol - edit->buffer.curs1);
1605         if (!edit_line_is_blank (edit, edit->buffer.curs_line))
1606         {
1607             if (option_fill_tabs_with_spaces)
1608                 insert_spaces_tab (edit, option_fake_half_tabs);
1609             else
1610                 edit_insert (edit, '\t');
1611             edit_cursor_move (edit,
1612                               edit_buffer_get_bol (&edit->buffer, cur_bol) - edit->buffer.curs1);
1613         }
1614 
1615         if (cur_bol == 0)
1616             break;
1617 
1618         cur_bol = edit_buffer_get_bol (&edit->buffer, cur_bol - 1);
1619     }
1620     while (cur_bol >= start_bol);
1621 
1622     edit->force |= REDRAW_PAGE;
1623 }
1624 
1625 /* --------------------------------------------------------------------------------------------- */
1626 
1627 static void
1628 edit_move_block_to_left (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1629 {
1630     off_t start_mark, end_mark;
1631     off_t cur_bol, start_bol;
1632 
1633     if (!eval_marks (edit, &start_mark, &end_mark))
1634         return;
1635 
1636     start_bol = edit_buffer_get_bol (&edit->buffer, start_mark);
1637     cur_bol = edit_buffer_get_bol (&edit->buffer, end_mark - 1);
1638 
1639     do
1640     {
1641         int del_tab_width;
1642         int next_char;
1643 
1644         edit_cursor_move (edit, cur_bol - edit->buffer.curs1);
1645 
1646         if (option_fake_half_tabs)
1647             del_tab_width = HALF_TAB_SIZE;
1648         else
1649             del_tab_width = option_tab_spacing;
1650 
1651         next_char = edit_buffer_get_current_byte (&edit->buffer);
1652         if (next_char == '\t')
1653             edit_delete (edit, TRUE);
1654         else if (next_char == ' ')
1655         {
1656             int i;
1657 
1658             for (i = 0; i < del_tab_width; i++)
1659             {
1660                 if (next_char == ' ')
1661                     edit_delete (edit, TRUE);
1662                 next_char = edit_buffer_get_current_byte (&edit->buffer);
1663             }
1664         }
1665 
1666         if (cur_bol == 0)
1667             break;
1668 
1669         cur_bol = edit_buffer_get_bol (&edit->buffer, cur_bol - 1);
1670     }
1671     while (cur_bol >= start_bol);
1672 
1673     edit->force |= REDRAW_PAGE;
1674 }
1675 
1676 /* --------------------------------------------------------------------------------------------- */
1677 /**
1678  * prints at the cursor
1679  * @return number of chars printed
1680  */
1681 
1682 static size_t
1683 edit_print_string (WEdit * e, const char *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
1684 {
1685     size_t i = 0;
1686 
1687     while (s[i] != '\0')
1688         edit_execute_cmd (e, CK_InsertChar, (unsigned char) s[i++]);
1689     e->force |= REDRAW_COMPLETELY;
1690     edit_update_screen (e);
1691     return i;
1692 }
1693 
1694 /* --------------------------------------------------------------------------------------------- */
1695 
1696 static off_t
1697 edit_insert_column_from_file (WEdit * edit, int file, off_t * start_pos, off_t * end_pos,
     /* [previous][next][first][last][top][bottom][index][help]  */
1698                               long *col1, long *col2)
1699 {
1700     off_t cursor;
1701     long col;
1702     off_t blocklen = -1, width = 0;
1703     unsigned char *data;
1704 
1705     cursor = edit->buffer.curs1;
1706     col = edit_get_col (edit);
1707     data = g_malloc0 (TEMP_BUF_LEN);
1708 
1709     while ((blocklen = mc_read (file, (char *) data, TEMP_BUF_LEN)) > 0)
1710     {
1711         off_t i;
1712         char *pn;
1713 
1714         pn = strchr ((char *) data, '\n');
1715         width = pn == NULL ? blocklen : pn - (char *) data;
1716 
1717         for (i = 0; i < blocklen; i++)
1718         {
1719             if (data[i] != '\n')
1720                 edit_insert (edit, data[i]);
1721             else
1722             {                   /* fill in and move to next line */
1723                 long l;
1724                 off_t p;
1725 
1726                 if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
1727                     for (l = width - (edit_get_col (edit) - col); l > 0; l -= space_width)
1728                         edit_insert (edit, ' ');
1729 
1730                 for (p = edit->buffer.curs1;; p++)
1731                 {
1732                     if (p == edit->buffer.size)
1733                     {
1734                         edit_cursor_move (edit, edit->buffer.size - edit->buffer.curs1);
1735                         edit_insert_ahead (edit, '\n');
1736                         p++;
1737                         break;
1738                     }
1739                     if (edit_buffer_get_byte (&edit->buffer, p) == '\n')
1740                     {
1741                         p++;
1742                         break;
1743                     }
1744                 }
1745 
1746                 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->buffer.curs1);
1747 
1748                 for (l = col - edit_get_col (edit); l >= space_width; l -= space_width)
1749                     edit_insert (edit, ' ');
1750             }
1751         }
1752     }
1753     *col1 = col;
1754     *col2 = col + width;
1755     *start_pos = cursor;
1756     *end_pos = edit->buffer.curs1;
1757     edit_cursor_move (edit, cursor - edit->buffer.curs1);
1758     g_free (data);
1759 
1760     return blocklen;
1761 }
1762 
1763 /* --------------------------------------------------------------------------------------------- */
1764 /*** public functions ****************************************************************************/
1765 /* --------------------------------------------------------------------------------------------- */
1766 
1767 /** User edit menu, like user menu (F2) but only in editor. */
1768 
1769 void
1770 user_menu (WEdit * edit, const char *menu_file, int selected_entry)
     /* [previous][next][first][last][top][bottom][index][help]  */
1771 {
1772     char *block_file;
1773     gboolean nomark;
1774     off_t curs;
1775     off_t start_mark, end_mark;
1776     struct stat status;
1777     vfs_path_t *block_file_vpath;
1778 
1779     block_file = mc_config_get_full_path (EDIT_HOME_BLOCK_FILE);
1780     block_file_vpath = vfs_path_from_str (block_file);
1781     curs = edit->buffer.curs1;
1782     nomark = !eval_marks (edit, &start_mark, &end_mark);
1783     if (!nomark)
1784         edit_save_block (edit, block_file, start_mark, end_mark);
1785 
1786     /* run shell scripts from menu */
1787     if (user_menu_cmd (edit, menu_file, selected_entry)
1788         && (mc_stat (block_file_vpath, &status) == 0) && (status.st_size != 0))
1789     {
1790         int rc = 0;
1791         FILE *fd;
1792 
1793         /* i.e. we have marked block */
1794         if (!nomark)
1795             rc = edit_block_delete_cmd (edit);
1796 
1797         if (rc == 0)
1798         {
1799             off_t ins_len;
1800 
1801             ins_len = edit_insert_file (edit, block_file_vpath);
1802             if (!nomark && ins_len > 0)
1803                 edit_set_markers (edit, start_mark, start_mark + ins_len, 0, 0);
1804         }
1805         /* truncate block file */
1806         fd = fopen (block_file, "w");
1807         if (fd != NULL)
1808             fclose (fd);
1809     }
1810     g_free (block_file);
1811     vfs_path_free (block_file_vpath, TRUE);
1812 
1813     edit_cursor_move (edit, curs - edit->buffer.curs1);
1814     edit->force |= REDRAW_PAGE;
1815     widget_draw (WIDGET (edit));
1816 }
1817 
1818 /* --------------------------------------------------------------------------------------------- */
1819 
1820 char *
1821 edit_get_write_filter (const vfs_path_t * write_name_vpath, const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1822 {
1823     int i;
1824     char *p, *writename;
1825     const vfs_path_element_t *path_element;
1826 
1827     i = edit_find_filter (filename_vpath);
1828     if (i < 0)
1829         return NULL;
1830 
1831     path_element = vfs_path_get_by_index (write_name_vpath, -1);
1832     writename = name_quote (path_element->path, FALSE);
1833     p = g_strdup_printf (all_filters[i].write, writename);
1834     g_free (writename);
1835     return p;
1836 }
1837 
1838 /* --------------------------------------------------------------------------------------------- */
1839 /**
1840  * @param edit   editor object
1841  * @param f      value of stream file
1842  * @return       the length of the file
1843  */
1844 
1845 off_t
1846 edit_write_stream (WEdit * edit, FILE * f)
     /* [previous][next][first][last][top][bottom][index][help]  */
1847 {
1848     long i;
1849 
1850     if (edit->lb == LB_ASIS)
1851     {
1852         for (i = 0; i < edit->buffer.size; i++)
1853             if (fputc (edit_buffer_get_byte (&edit->buffer, i), f) < 0)
1854                 break;
1855         return i;
1856     }
1857 
1858     /* change line breaks */
1859     for (i = 0; i < edit->buffer.size; i++)
1860     {
1861         unsigned char c;
1862 
1863         c = edit_buffer_get_byte (&edit->buffer, i);
1864         if (!(c == '\n' || c == '\r'))
1865         {
1866             /* not line break */
1867             if (fputc (c, f) < 0)
1868                 return i;
1869         }
1870         else
1871         {                       /* (c == '\n' || c == '\r') */
1872             unsigned char c1;
1873 
1874             c1 = edit_buffer_get_byte (&edit->buffer, i + 1);   /* next char */
1875 
1876             switch (edit->lb)
1877             {
1878             case LB_UNIX:      /* replace "\r\n" or '\r' to '\n' */
1879                 /* put one line break unconditionally */
1880                 if (fputc ('\n', f) < 0)
1881                     return i;
1882 
1883                 i++;            /* 2 chars are processed */
1884 
1885                 if (c == '\r' && c1 == '\n')
1886                     /* Windows line break; go to the next char */
1887                     break;
1888 
1889                 if (c == '\r' && c1 == '\r')
1890                 {
1891                     /* two Macintosh line breaks; put second line break */
1892                     if (fputc ('\n', f) < 0)
1893                         return i;
1894                     break;
1895                 }
1896 
1897                 if (fputc (c1, f) < 0)
1898                     return i;
1899                 break;
1900 
1901             case LB_WIN:       /* replace '\n' or '\r' to "\r\n" */
1902                 /* put one line break unconditionally */
1903                 if (fputc ('\r', f) < 0 || fputc ('\n', f) < 0)
1904                     return i;
1905 
1906                 if (c == '\r' && c1 == '\n')
1907                     /* Windows line break; go to the next char */
1908                     i++;
1909                 break;
1910 
1911             case LB_MAC:       /* replace "\r\n" or '\n' to '\r' */
1912                 /* put one line break unconditionally */
1913                 if (fputc ('\r', f) < 0)
1914                     return i;
1915 
1916                 i++;            /* 2 chars are processed */
1917 
1918                 if (c == '\r' && c1 == '\n')
1919                     /* Windows line break; go to the next char */
1920                     break;
1921 
1922                 if (c == '\n' && c1 == '\n')
1923                 {
1924                     /* two Windows line breaks; put second line break */
1925                     if (fputc ('\r', f) < 0)
1926                         return i;
1927                     break;
1928                 }
1929 
1930                 if (fputc (c1, f) < 0)
1931                     return i;
1932                 break;
1933             case LB_ASIS:      /* default without changes */
1934             default:
1935                 break;
1936             }
1937         }
1938     }
1939 
1940     return edit->buffer.size;
1941 }
1942 
1943 /* --------------------------------------------------------------------------------------------- */
1944 
1945 gboolean
1946 is_break_char (char c)
     /* [previous][next][first][last][top][bottom][index][help]  */
1947 {
1948     return (isspace (c) || strchr ("{}[]()<>=|/\\!?~-+`'\",.;:#$%^&*", c));
1949 }
1950 
1951 /* --------------------------------------------------------------------------------------------- */
1952 /** inserts a file at the cursor, returns count of inserted bytes on success */
1953 
1954 off_t
1955 edit_insert_file (WEdit * edit, const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1956 {
1957     char *p;
1958     off_t current;
1959     off_t ins_len = 0;
1960 
1961     p = edit_get_filter (filename_vpath);
1962     current = edit->buffer.curs1;
1963 
1964     if (p != NULL)
1965     {
1966         FILE *f;
1967 
1968         f = (FILE *) popen (p, "r");
1969         if (f != NULL)
1970         {
1971             edit_insert_stream (edit, f);
1972 
1973             /* Place cursor at the end of text selection */
1974             if (!option_cursor_after_inserted_block)
1975             {
1976                 ins_len = edit->buffer.curs1 - current;
1977                 edit_cursor_move (edit, -ins_len);
1978             }
1979             if (pclose (f) > 0)
1980             {
1981                 char *errmsg;
1982 
1983                 errmsg = g_strdup_printf (_("Error reading from pipe: %s"), p);
1984                 edit_error_dialog (_("Error"), errmsg);
1985                 g_free (errmsg);
1986                 ins_len = -1;
1987             }
1988         }
1989         else
1990         {
1991             char *errmsg;
1992 
1993             errmsg = g_strdup_printf (_("Cannot open pipe for reading: %s"), p);
1994             edit_error_dialog (_("Error"), errmsg);
1995             g_free (errmsg);
1996             ins_len = -1;
1997         }
1998         g_free (p);
1999     }
2000     else
2001     {
2002         int file;
2003         off_t blocklen;
2004         int vertical_insertion = 0;
2005         char *buf;
2006 
2007         file = mc_open (filename_vpath, O_RDONLY | O_BINARY);
2008         if (file == -1)
2009             return -1;
2010 
2011         buf = g_malloc0 (TEMP_BUF_LEN);
2012         blocklen = mc_read (file, buf, sizeof (VERTICAL_MAGIC));
2013         if (blocklen > 0)
2014         {
2015             /* if contain signature VERTICAL_MAGIC then it vertical block */
2016             if (memcmp (buf, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC)) == 0)
2017                 vertical_insertion = 1;
2018             else
2019                 mc_lseek (file, 0, SEEK_SET);
2020         }
2021 
2022         if (vertical_insertion)
2023         {
2024             off_t mark1, mark2;
2025             long c1, c2;
2026 
2027             blocklen = edit_insert_column_from_file (edit, file, &mark1, &mark2, &c1, &c2);
2028             edit_set_markers (edit, edit->buffer.curs1, mark2, c1, c2);
2029 
2030             /* highlight inserted text then not persistent blocks */
2031             if (!option_persistent_selections && edit->modified)
2032             {
2033                 if (!edit->column_highlight)
2034                     edit_push_undo_action (edit, COLUMN_OFF);
2035                 edit->column_highlight = 1;
2036             }
2037         }
2038         else
2039         {
2040             off_t i;
2041 
2042             while ((blocklen = mc_read (file, (char *) buf, TEMP_BUF_LEN)) > 0)
2043             {
2044                 for (i = 0; i < blocklen; i++)
2045                     edit_insert (edit, buf[i]);
2046             }
2047             /* highlight inserted text then not persistent blocks */
2048             if (!option_persistent_selections && edit->modified)
2049             {
2050                 edit_set_markers (edit, edit->buffer.curs1, current, 0, 0);
2051                 if (edit->column_highlight)
2052                     edit_push_undo_action (edit, COLUMN_ON);
2053                 edit->column_highlight = 0;
2054             }
2055 
2056             /* Place cursor at the end of text selection */
2057             if (!option_cursor_after_inserted_block)
2058             {
2059                 ins_len = edit->buffer.curs1 - current;
2060                 edit_cursor_move (edit, -ins_len);
2061             }
2062         }
2063 
2064         edit->force |= REDRAW_PAGE;
2065         g_free (buf);
2066         mc_close (file);
2067         if (blocklen != 0)
2068             ins_len = 0;
2069     }
2070 
2071     return ins_len;
2072 }
2073 
2074 /* --------------------------------------------------------------------------------------------- */
2075 /**
2076  * Fill in the edit structure.  Return NULL on failure.  Pass edit as
2077  * NULL to allocate a new structure.
2078  *
2079  * If line is 0, try to restore saved position.  Otherwise put the
2080  * cursor on that line and show it in the middle of the screen.
2081  */
2082 
2083 WEdit *
2084 edit_init (WEdit * edit, const WRect * r, const vfs_path_t * filename_vpath, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
2085 {
2086     gboolean to_free = FALSE;
2087 
2088     option_auto_syntax = TRUE;  /* Resetting to auto on every invokation */
2089     option_line_state_width = option_line_state ? LINE_STATE_WIDTH : 0;
2090 
2091     if (edit != NULL)
2092     {
2093         gboolean fullscreen;
2094         WRect loc_prev;
2095 
2096         /* save some widget parameters */
2097         fullscreen = edit->fullscreen;
2098         loc_prev = edit->loc_prev;
2099 
2100         edit_purge_widget (edit);
2101 
2102         /* restore saved parameters */
2103         edit->fullscreen = fullscreen;
2104         edit->loc_prev = loc_prev;
2105     }
2106     else
2107     {
2108         Widget *w;
2109 
2110         edit = g_malloc0 (sizeof (WEdit));
2111         to_free = TRUE;
2112 
2113         w = WIDGET (edit);
2114         widget_init (w, r, NULL, NULL);
2115         w->options |= WOP_SELECTABLE | WOP_TOP_SELECT | WOP_WANT_CURSOR;
2116         w->keymap = editor_map;
2117         w->ext_keymap = editor_x_map;
2118         edit->fullscreen = TRUE;
2119         edit_save_size (edit);
2120     }
2121 
2122     edit->drag_state = MCEDIT_DRAG_NONE;
2123 
2124     edit->stat1.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
2125     edit->stat1.st_uid = getuid ();
2126     edit->stat1.st_gid = getgid ();
2127     edit->stat1.st_mtime = 0;
2128 
2129     edit->over_col = 0;
2130     edit->bracket = -1;
2131     edit->last_bracket = -1;
2132     edit->force |= REDRAW_PAGE;
2133 
2134     /* set file name before load file */
2135     edit_set_filename (edit, filename_vpath);
2136 
2137     edit->undo_stack_size = START_STACK_SIZE;
2138     edit->undo_stack_size_mask = START_STACK_SIZE - 1;
2139     edit->undo_stack = g_malloc0 ((edit->undo_stack_size + 10) * sizeof (long));
2140 
2141     edit->redo_stack_size = START_STACK_SIZE;
2142     edit->redo_stack_size_mask = START_STACK_SIZE - 1;
2143     edit->redo_stack = g_malloc0 ((edit->redo_stack_size + 10) * sizeof (long));
2144 
2145 #ifdef HAVE_CHARSET
2146     edit->utf8 = FALSE;
2147     edit->converter = str_cnv_from_term;
2148     edit_set_codeset (edit);
2149 #endif
2150 
2151     if (!edit_load_file (edit))
2152     {
2153         /* edit_load_file already gives an error message */
2154         if (to_free)
2155             g_free (edit);
2156         return NULL;
2157     }
2158 
2159     edit->loading_done = 1;
2160     edit->modified = 0;
2161     edit->locked = 0;
2162     edit_load_syntax (edit, NULL, NULL);
2163     edit_get_syntax_color (edit, -1);
2164 
2165     /* load saved cursor position and/or boolmarks */
2166     if ((line == 0) && option_save_position)
2167         edit_load_position (edit, TRUE);
2168     else
2169     {
2170         edit_load_position (edit, FALSE);
2171         if (line <= 0)
2172             line = 1;
2173         edit_move_display (edit, line - 1);
2174         edit_move_to_line (edit, line - 1);
2175     }
2176 
2177     edit_load_macro_cmd (edit);
2178 
2179     return edit;
2180 }
2181 
2182 /* --------------------------------------------------------------------------------------------- */
2183 
2184 /** Clear the edit struct, freeing everything in it.  Return TRUE on success */
2185 gboolean
2186 edit_clean (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2187 {
2188     if (edit == NULL)
2189         return FALSE;
2190 
2191     /* a stale lock, remove it */
2192     if (edit->locked)
2193         (void) unlock_file (edit->filename_vpath);
2194 
2195     /* save cursor position */
2196     if (option_save_position)
2197         edit_save_position (edit);
2198     else if (edit->serialized_bookmarks != NULL)
2199         g_array_free (edit->serialized_bookmarks, TRUE);
2200 
2201     /* File specified on the mcedit command line and never saved */
2202     if (edit->delete_file)
2203         unlink (vfs_path_get_last_path_str (edit->filename_vpath));
2204 
2205     edit_free_syntax_rules (edit);
2206     book_mark_flush (edit, -1);
2207 
2208     edit_buffer_clean (&edit->buffer);
2209 
2210     g_free (edit->undo_stack);
2211     g_free (edit->redo_stack);
2212     vfs_path_free (edit->filename_vpath, TRUE);
2213     vfs_path_free (edit->dir_vpath, TRUE);
2214     edit_search_deinit (edit);
2215 
2216 #ifdef HAVE_CHARSET
2217     if (edit->converter != str_cnv_from_term)
2218         str_close_conv (edit->converter);
2219 #endif
2220 
2221     edit_purge_widget (edit);
2222 
2223     return TRUE;
2224 }
2225 
2226 /* --------------------------------------------------------------------------------------------- */
2227 
2228 /**
2229  * Load a new file into the editor and set line.  If it fails, preserve the old file.
2230  * To do it, allocate a new widget, initialize it and, if the new file
2231  * was loaded, copy the data to the old widget.
2232  *
2233  * @return TRUE on success, FALSE on failure.
2234  */
2235 gboolean
2236 edit_reload_line (WEdit * edit, const vfs_path_t * filename_vpath, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
2237 {
2238     Widget *w = WIDGET (edit);
2239     WEdit *e;
2240 
2241     e = g_malloc0 (sizeof (WEdit));
2242     *WIDGET (e) = *w;
2243     /* save some widget parameters */
2244     e->fullscreen = edit->fullscreen;
2245     e->loc_prev = edit->loc_prev;
2246 
2247     if (edit_init (e, &w->rect, filename_vpath, line) == NULL)
2248     {
2249         g_free (e);
2250         return FALSE;
2251     }
2252 
2253     edit_clean (edit);
2254     memcpy (edit, e, sizeof (*edit));
2255     g_free (e);
2256 
2257     return TRUE;
2258 }
2259 
2260 /* --------------------------------------------------------------------------------------------- */
2261 
2262 #ifdef HAVE_CHARSET
2263 void
2264 edit_set_codeset (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2265 {
2266     const char *cp_id;
2267 
2268     cp_id =
2269         get_codepage_id (mc_global.source_codepage >=
2270                          0 ? mc_global.source_codepage : mc_global.display_codepage);
2271 
2272     if (cp_id != NULL)
2273     {
2274         GIConv conv;
2275         conv = str_crt_conv_from (cp_id);
2276         if (conv != INVALID_CONV)
2277         {
2278             if (edit->converter != str_cnv_from_term)
2279                 str_close_conv (edit->converter);
2280             edit->converter = conv;
2281         }
2282     }
2283 
2284     if (cp_id != NULL)
2285         edit->utf8 = str_isutf8 (cp_id);
2286 }
2287 #endif
2288 
2289 /* --------------------------------------------------------------------------------------------- */
2290 
2291 /**
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
2296  * delete etc.
2297  *
2298  * eg:
2299  *
2300  * pushed:       stored:
2301  *
2302  * a
2303  * b             a
2304  * b            -3
2305  * b             b
2306  * c  -->       -4
2307  * c             c
2308  * c             d
2309  * c
2310  * d
2311  *
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
2316  * position.
2317  *
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
2321  * called.
2322  *
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)
2328  *
2329  *
2330  *
2331  * @param edit editor object
2332  * @param c code of the action
2333  */
2334 
2335 void
2336 edit_push_undo_action (WEdit * edit, long c)
     /* [previous][next][first][last][top][bottom][index][help]  */
2337 {
2338     unsigned long sp = edit->undo_stack_pointer;
2339     unsigned long spm1;
2340     long *t;
2341 
2342     /* first enlarge the stack if necessary */
2343     if (sp > edit->undo_stack_size - 10)
2344     {                           /* say */
2345         if (option_max_undo < 256)
2346             option_max_undo = 256;
2347         if (edit->undo_stack_size < (unsigned long) option_max_undo)
2348         {
2349             t = g_realloc (edit->undo_stack, (edit->undo_stack_size * 2 + 10) * sizeof (long));
2350             if (t)
2351             {
2352                 edit->undo_stack = t;
2353                 edit->undo_stack_size <<= 1;
2354                 edit->undo_stack_size_mask = edit->undo_stack_size - 1;
2355             }
2356         }
2357     }
2358     spm1 = (edit->undo_stack_pointer - 1) & edit->undo_stack_size_mask;
2359     if (edit->undo_stack_disable)
2360     {
2361         edit_push_redo_action (edit, KEY_PRESS);
2362         edit_push_redo_action (edit, c);
2363         return;
2364     }
2365 
2366     if (edit->redo_stack_reset)
2367         edit->redo_stack_bottom = edit->redo_stack_pointer = 0;
2368 
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)
2372     {
2373         long d;
2374         if (edit->undo_stack[spm1] < 0)
2375         {
2376             d = edit->undo_stack[(sp - 2) & edit->undo_stack_size_mask];
2377             if (d == c && edit->undo_stack[spm1] > -1000000000)
2378             {
2379                 if (c < KEY_PRESS)      /* --> no need to push multiple do-nothings */
2380                     edit->undo_stack[spm1]--;
2381                 return;
2382             }
2383         }
2384         else
2385         {
2386             d = edit->undo_stack[spm1];
2387             if (d == c)
2388             {
2389                 if (c >= KEY_PRESS)
2390                     return;     /* --> no need to push multiple do-nothings */
2391                 edit->undo_stack[sp] = -2;
2392                 goto check_bottom;
2393             }
2394         }
2395     }
2396     edit->undo_stack[sp] = c;
2397 
2398   check_bottom:
2399     edit->undo_stack_pointer = (edit->undo_stack_pointer + 1) & edit->undo_stack_size_mask;
2400 
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)
2407         do
2408         {
2409             edit->undo_stack_bottom = (edit->undo_stack_bottom + 1) & edit->undo_stack_size_mask;
2410         }
2411         while (edit->undo_stack[edit->undo_stack_bottom] < KEY_PRESS
2412                && edit->undo_stack_bottom != edit->undo_stack_pointer);
2413 
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)
2417     {
2418         edit->undo_stack_bottom = edit->undo_stack_pointer = 0;
2419     }
2420 }
2421 
2422 /* --------------------------------------------------------------------------------------------- */
2423 
2424 void
2425 edit_push_redo_action (WEdit * edit, long c)
     /* [previous][next][first][last][top][bottom][index][help]  */
2426 {
2427     unsigned long sp = edit->redo_stack_pointer;
2428     unsigned long spm1;
2429     long *t;
2430     /* first enlarge the stack if necessary */
2431     if (sp > edit->redo_stack_size - 10)
2432     {                           /* say */
2433         if (option_max_undo < 256)
2434             option_max_undo = 256;
2435         if (edit->redo_stack_size < (unsigned long) option_max_undo)
2436         {
2437             t = g_realloc (edit->redo_stack, (edit->redo_stack_size * 2 + 10) * sizeof (long));
2438             if (t)
2439             {
2440                 edit->redo_stack = t;
2441                 edit->redo_stack_size <<= 1;
2442                 edit->redo_stack_size_mask = edit->redo_stack_size - 1;
2443             }
2444         }
2445     }
2446     spm1 = (edit->redo_stack_pointer - 1) & edit->redo_stack_size_mask;
2447 
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)
2451     {
2452         long d;
2453         if (edit->redo_stack[spm1] < 0)
2454         {
2455             d = edit->redo_stack[(sp - 2) & edit->redo_stack_size_mask];
2456             if (d == c && edit->redo_stack[spm1] > -1000000000)
2457             {
2458                 if (c < KEY_PRESS)      /* --> no need to push multiple do-nothings */
2459                     edit->redo_stack[spm1]--;
2460                 return;
2461             }
2462         }
2463         else
2464         {
2465             d = edit->redo_stack[spm1];
2466             if (d == c)
2467             {
2468                 if (c >= KEY_PRESS)
2469                     return;     /* --> no need to push multiple do-nothings */
2470                 edit->redo_stack[sp] = -2;
2471                 goto redo_check_bottom;
2472             }
2473         }
2474     }
2475     edit->redo_stack[sp] = c;
2476 
2477   redo_check_bottom:
2478     edit->redo_stack_pointer = (edit->redo_stack_pointer + 1) & edit->redo_stack_size_mask;
2479 
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)
2486         do
2487         {
2488             edit->redo_stack_bottom = (edit->redo_stack_bottom + 1) & edit->redo_stack_size_mask;
2489         }
2490         while (edit->redo_stack[edit->redo_stack_bottom] < KEY_PRESS
2491                && edit->redo_stack_bottom != edit->redo_stack_pointer);
2492 
2493     /*
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:
2497      */
2498 
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;
2502 }
2503 
2504 /* --------------------------------------------------------------------------------------------- */
2505 /**
2506    Basic low level single character buffer alterations and movements at the cursor.
2507  */
2508 
2509 void
2510 edit_insert (WEdit * edit, int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
2511 {
2512     /* first we must update the position of the display window */
2513     if (edit->buffer.curs1 < edit->start_display)
2514     {
2515         edit->start_display++;
2516         if (c == '\n')
2517             edit->start_line++;
2518     }
2519 
2520     /* Mark file as modified, unless the file hasn't been fully loaded */
2521     if (edit->loading_done)
2522         edit_modification (edit);
2523 
2524     /* now we must update some info on the file and check if a redraw is required */
2525     if (c == '\n')
2526     {
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;
2531     }
2532 
2533     /* save the reverse command onto the undo stack */
2534     /* ordinary char and not space */
2535     if (c > 32)
2536         edit_push_undo_action (edit, BACKSPACE);
2537     else
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;
2543 
2544     edit_buffer_insert (&edit->buffer, c);
2545 }
2546 
2547 /* --------------------------------------------------------------------------------------------- */
2548 /** same as edit_insert and move left */
2549 
2550 void
2551 edit_insert_ahead (WEdit * edit, int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
2552 {
2553     if (edit->buffer.curs1 < edit->start_display)
2554     {
2555         edit->start_display++;
2556         if (c == '\n')
2557             edit->start_line++;
2558     }
2559     edit_modification (edit);
2560     if (c == '\n')
2561     {
2562         book_mark_inc (edit, edit->buffer.curs_line);
2563         edit->buffer.lines++;
2564         edit->force |= REDRAW_AFTER_CURSOR;
2565     }
2566     /* ordinary char and not space */
2567     if (c > 32)
2568         edit_push_undo_action (edit, DELCHAR);
2569     else
2570         edit_push_undo_action (edit, DELCHAR_BR);
2571 
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;
2575 
2576     edit_buffer_insert_ahead (&edit->buffer, c);
2577 }
2578 
2579 /* --------------------------------------------------------------------------------------------- */
2580 
2581 void
2582 edit_insert_over (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2583 {
2584     long i;
2585 
2586     for (i = 0; i < edit->over_col; i++)
2587         edit_insert (edit, ' ');
2588 
2589     edit->over_col = 0;
2590 }
2591 
2592 /* --------------------------------------------------------------------------------------------- */
2593 
2594 int
2595 edit_delete (WEdit * edit, gboolean byte_delete)
     /* [previous][next][first][last][top][bottom][index][help]  */
2596 {
2597     int p = 0;
2598     int char_length = 1;
2599     int i;
2600 
2601     if (edit->buffer.curs2 == 0)
2602         return 0;
2603 
2604 #ifdef HAVE_CHARSET
2605     /* if byte_delete == TRUE then delete only one byte not multibyte char */
2606     if (edit->utf8 && !byte_delete)
2607     {
2608         edit_buffer_get_utf (&edit->buffer, edit->buffer.curs1, &char_length);
2609         if (char_length < 1)
2610             char_length = 1;
2611     }
2612 #else
2613     (void) byte_delete;
2614 #endif
2615 
2616     if (edit->mark2 != edit->mark1)
2617         edit_push_markers (edit);
2618 
2619     for (i = 1; i <= char_length; i++)
2620     {
2621         if (edit->mark1 > edit->buffer.curs1)
2622         {
2623             edit->mark1--;
2624             edit->end_mark_curs--;
2625         }
2626         if (edit->mark2 > edit->buffer.curs1)
2627             edit->mark2--;
2628         if (edit->last_get_rule > edit->buffer.curs1)
2629             edit->last_get_rule--;
2630 
2631         p = edit_buffer_delete (&edit->buffer);
2632 
2633         edit_push_undo_action (edit, p + 256);
2634     }
2635 
2636     edit_modification (edit);
2637     if (p == '\n')
2638     {
2639         book_mark_dec (edit, edit->buffer.curs_line);
2640         edit->buffer.lines--;
2641         edit->force |= REDRAW_AFTER_CURSOR;
2642     }
2643     if (edit->buffer.curs1 < edit->start_display)
2644     {
2645         edit->start_display--;
2646         if (p == '\n')
2647             edit->start_line--;
2648     }
2649 
2650     return p;
2651 }
2652 
2653 /* --------------------------------------------------------------------------------------------- */
2654 
2655 int
2656 edit_backspace (WEdit * edit, gboolean byte_delete)
     /* [previous][next][first][last][top][bottom][index][help]  */
2657 {
2658     int p = 0;
2659     int char_length = 1;
2660     int i;
2661 
2662     if (edit->buffer.curs1 == 0)
2663         return 0;
2664 
2665     if (edit->mark2 != edit->mark1)
2666         edit_push_markers (edit);
2667 
2668 #ifdef HAVE_CHARSET
2669     if (edit->utf8 && !byte_delete)
2670     {
2671         edit_buffer_get_prev_utf (&edit->buffer, edit->buffer.curs1, &char_length);
2672         if (char_length < 1)
2673             char_length = 1;
2674     }
2675 #else
2676     (void) byte_delete;
2677 #endif
2678 
2679     for (i = 1; i <= char_length; i++)
2680     {
2681         if (edit->mark1 >= edit->buffer.curs1)
2682         {
2683             edit->mark1--;
2684             edit->end_mark_curs--;
2685         }
2686         if (edit->mark2 >= edit->buffer.curs1)
2687             edit->mark2--;
2688         if (edit->last_get_rule >= edit->buffer.curs1)
2689             edit->last_get_rule--;
2690 
2691         p = edit_buffer_backspace (&edit->buffer);
2692 
2693         edit_push_undo_action (edit, p);
2694     }
2695     edit_modification (edit);
2696     if (p == '\n')
2697     {
2698         book_mark_dec (edit, edit->buffer.curs_line);
2699         edit->buffer.curs_line--;
2700         edit->buffer.lines--;
2701         edit->force |= REDRAW_AFTER_CURSOR;
2702     }
2703 
2704     if (edit->buffer.curs1 < edit->start_display)
2705     {
2706         edit->start_display--;
2707         if (p == '\n')
2708             edit->start_line--;
2709     }
2710 
2711     return p;
2712 }
2713 
2714 /* --------------------------------------------------------------------------------------------- */
2715 /** moves the cursor right or left: increment positive or negative respectively */
2716 
2717 void
2718 edit_cursor_move (WEdit * edit, off_t increment)
     /* [previous][next][first][last][top][bottom][index][help]  */
2719 {
2720     if (increment < 0)
2721     {
2722         for (; increment < 0 && edit->buffer.curs1 != 0; increment++)
2723         {
2724             int c;
2725 
2726             edit_push_undo_action (edit, CURS_RIGHT);
2727 
2728             c = edit_buffer_get_previous_byte (&edit->buffer);
2729             edit_buffer_insert_ahead (&edit->buffer, c);
2730             c = edit_buffer_backspace (&edit->buffer);
2731             if (c == '\n')
2732             {
2733                 edit->buffer.curs_line--;
2734                 edit->force |= REDRAW_LINE_BELOW;
2735             }
2736         }
2737     }
2738     else
2739     {
2740         for (; increment > 0 && edit->buffer.curs2 != 0; increment--)
2741         {
2742             int c;
2743 
2744             edit_push_undo_action (edit, CURS_LEFT);
2745 
2746             c = edit_buffer_get_current_byte (&edit->buffer);
2747             edit_buffer_insert (&edit->buffer, c);
2748             c = edit_buffer_delete (&edit->buffer);
2749             if (c == '\n')
2750             {
2751                 edit->buffer.curs_line++;
2752                 edit->force |= REDRAW_LINE_ABOVE;
2753             }
2754         }
2755     }
2756 }
2757 
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. */
2761 
2762 off_t
2763 edit_move_forward3 (const WEdit * edit, off_t current, long cols, off_t upto)
     /* [previous][next][first][last][top][bottom][index][help]  */
2764 {
2765     off_t p, q;
2766     long col;
2767 
2768     if (upto != 0)
2769     {
2770         q = upto;
2771         cols = -10;
2772     }
2773     else
2774         q = edit->buffer.size + 2;
2775 
2776     for (col = 0, p = current; p < q; p++)
2777     {
2778         int c, orig_c;
2779 
2780         if (cols != -10)
2781         {
2782             if (col == cols)
2783                 return p;
2784             if (col > cols)
2785                 return p - 1;
2786         }
2787 
2788         orig_c = c = edit_buffer_get_byte (&edit->buffer, p);
2789 
2790 #ifdef HAVE_CHARSET
2791         if (edit->utf8)
2792         {
2793             int utf_ch;
2794             int char_length = 1;
2795 
2796             utf_ch = edit_buffer_get_utf (&edit->buffer, p, &char_length);
2797             if (mc_global.utf8_display)
2798             {
2799                 if (char_length > 1)
2800                     col -= char_length - 1;
2801                 if (g_unichar_iswide (utf_ch))
2802                     col++;
2803             }
2804             else if (char_length > 1 && g_unichar_isprint (utf_ch))
2805                 col -= char_length - 1;
2806         }
2807 
2808         c = convert_to_display_c (c);
2809 #endif
2810 
2811         if (c == '\n')
2812             return (upto != 0 ? (off_t) col : p);
2813         if (c == '\t')
2814             col += TAB_SIZE - col % TAB_SIZE;
2815         else if ((c < 32 || c == 127) && (orig_c == c
2816 #ifdef HAVE_CHARSET
2817                                           || (!mc_global.utf8_display && !edit->utf8)
2818 #endif
2819                  ))
2820             /* '\r' is shown as ^M, so we must advance 2 characters */
2821             /* Caret notation for control characters */
2822             col += 2;
2823         else
2824             col++;
2825     }
2826     return (off_t) col;
2827 }
2828 
2829 /* --------------------------------------------------------------------------------------------- */
2830 /** returns the current offset of the cursor from the beginning of a file */
2831 
2832 off_t
2833 edit_get_cursor_offset (const WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2834 {
2835     return edit->buffer.curs1;
2836 }
2837 
2838 /* --------------------------------------------------------------------------------------------- */
2839 /** returns the current column position of the cursor */
2840 
2841 long
2842 edit_get_col (const WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2843 {
2844     return (long) edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), 0,
2845                                       edit->buffer.curs1);
2846 }
2847 
2848 /* --------------------------------------------------------------------------------------------- */
2849 /* Scrolling functions */
2850 /* --------------------------------------------------------------------------------------------- */
2851 
2852 void
2853 edit_update_curs_row (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2854 {
2855     edit->curs_row = edit->buffer.curs_line - edit->start_line;
2856 }
2857 
2858 /* --------------------------------------------------------------------------------------------- */
2859 
2860 void
2861 edit_update_curs_col (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2862 {
2863     edit->curs_col = (long) edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer),
2864                                                 0, edit->buffer.curs1);
2865 }
2866 
2867 /* --------------------------------------------------------------------------------------------- */
2868 
2869 long
2870 edit_get_curs_col (const WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
2871 {
2872     return edit->curs_col;
2873 }
2874 
2875 /* --------------------------------------------------------------------------------------------- */
2876 /** moves the display start position up by i lines */
2877 
2878 void
2879 edit_scroll_upward (WEdit * edit, long i)
     /* [previous][next][first][last][top][bottom][index][help]  */
2880 {
2881     long lines_above = edit->start_line;
2882 
2883     if (i > lines_above)
2884         i = lines_above;
2885     if (i != 0)
2886     {
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);
2892     }
2893     edit_update_curs_row (edit);
2894 }
2895 
2896 
2897 /* --------------------------------------------------------------------------------------------- */
2898 
2899 void
2900 edit_scroll_downward (WEdit * edit, long i)
     /* [previous][next][first][last][top][bottom][index][help]  */
2901 {
2902     long lines_below;
2903 
2904     lines_below = edit->buffer.lines - edit->start_line - (WIDGET (edit)->rect.lines - 1);
2905     if (lines_below > 0)
2906     {
2907         if (i > lines_below)
2908             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);
2914     }
2915     edit_update_curs_row (edit);
2916 }
2917 
2918 /* --------------------------------------------------------------------------------------------- */
2919 
2920 void
2921 edit_scroll_right (WEdit * edit, long i)
     /* [previous][next][first][last][top][bottom][index][help]  */
2922 {
2923     edit->force |= REDRAW_PAGE;
2924     edit->force &= (0xfff - REDRAW_CHAR_ONLY);
2925     edit->start_col -= i;
2926 }
2927 
2928 /* --------------------------------------------------------------------------------------------- */
2929 
2930 void
2931 edit_scroll_left (WEdit * edit, long i)
     /* [previous][next][first][last][top][bottom][index][help]  */
2932 {
2933     if (edit->start_col)
2934     {
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);
2940     }
2941 }
2942 
2943 /* --------------------------------------------------------------------------------------------- */
2944 /* high level cursor movement commands */
2945 /* --------------------------------------------------------------------------------------------- */
2946 
2947 void
2948 edit_move_to_prev_col (WEdit * edit, off_t p)
     /* [previous][next][first][last][top][bottom][index][help]  */
2949 {
2950     long prev = edit->prev_col;
2951     long over = edit->over_col;
2952 
2953     edit_cursor_move (edit,
2954                       edit_move_forward3 (edit, p, prev + edit->over_col, 0) - edit->buffer.curs1);
2955 
2956     if (option_cursor_beyond_eol)
2957     {
2958         long line_len;
2959 
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)
2963         {
2964             edit->over_col = prev + over - line_len;
2965             edit->prev_col = line_len;
2966             edit->curs_col = line_len;
2967         }
2968         else
2969         {
2970             edit->curs_col = prev + over;
2971             edit->prev_col = edit->curs_col;
2972             edit->over_col = 0;
2973         }
2974     }
2975     else
2976     {
2977         edit->over_col = 0;
2978         if (option_fake_half_tabs && is_in_indent (&edit->buffer))
2979         {
2980             long fake_half_tabs;
2981 
2982             edit_update_curs_col (edit);
2983 
2984             fake_half_tabs = HALF_TAB_SIZE * space_width;
2985             if (fake_half_tabs != 0 && edit->curs_col % fake_half_tabs != 0)
2986             {
2987                 long q;
2988 
2989                 q = edit->curs_col;
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);
2998             }
2999         }
3000     }
3001 }
3002 
3003 /* --------------------------------------------------------------------------------------------- */
3004 /** check whether line in editor is blank or not
3005  *
3006  * @param edit editor object
3007  * @param line number of line
3008  *
3009  * @return TRUE if line in blank, FALSE otherwise
3010  */
3011 
3012 gboolean
3013 edit_line_is_blank (WEdit * edit, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
3014 {
3015     return is_blank (&edit->buffer, edit_find_line (edit, line));
3016 }
3017 
3018 /* --------------------------------------------------------------------------------------------- */
3019 /** move cursor to line 'line' */
3020 
3021 void
3022 edit_move_to_line (WEdit * e, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
3023 {
3024     if (line < e->buffer.curs_line)
3025         edit_move_up (e, e->buffer.curs_line - line, FALSE);
3026     else
3027         edit_move_down (e, line - e->buffer.curs_line, FALSE);
3028     edit_scroll_screen_over_cursor (e);
3029 }
3030 
3031 /* --------------------------------------------------------------------------------------------- */
3032 /** scroll window so that first visible line is 'line' */
3033 
3034 void
3035 edit_move_display (WEdit * e, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
3036 {
3037     if (line < e->start_line)
3038         edit_scroll_upward (e, e->start_line - line);
3039     else
3040         edit_scroll_downward (e, line - e->start_line);
3041 }
3042 
3043 /* --------------------------------------------------------------------------------------------- */
3044 /** save markers onto undo stack */
3045 
3046 void
3047 edit_push_markers (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3048 {
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);
3052 }
3053 
3054 /* --------------------------------------------------------------------------------------------- */
3055 
3056 void
3057 edit_set_markers (WEdit * edit, off_t m1, off_t m2, long c1, long c2)
     /* [previous][next][first][last][top][bottom][index][help]  */
3058 {
3059     edit->mark1 = m1;
3060     edit->mark2 = m2;
3061     edit->column1 = c1;
3062     edit->column2 = c2;
3063 }
3064 
3065 
3066 /* --------------------------------------------------------------------------------------------- */
3067 /** highlight marker toggle */
3068 
3069 void
3070 edit_mark_cmd (WEdit * edit, gboolean unmark)
     /* [previous][next][first][last][top][bottom][index][help]  */
3071 {
3072     edit_push_markers (edit);
3073     if (unmark)
3074     {
3075         edit_set_markers (edit, 0, 0, 0, 0);
3076         edit->force |= REDRAW_PAGE;
3077     }
3078     else if (edit->mark2 >= 0)
3079     {
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;
3084     }
3085     else
3086     {
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);
3090     }
3091 }
3092 
3093 /* --------------------------------------------------------------------------------------------- */
3094 /** highlight the word under cursor */
3095 
3096 void
3097 edit_mark_current_word_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3098 {
3099     long pos;
3100 
3101     for (pos = edit->buffer.curs1; pos != 0; pos--)
3102     {
3103         int c1, c2;
3104 
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))
3108             break;
3109         if ((my_type_of (c1) & my_type_of (c2)) == 0)
3110             break;
3111     }
3112     edit->mark1 = pos;
3113 
3114     for (; pos < edit->buffer.size; pos++)
3115     {
3116         int c1, c2;
3117 
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))
3121             break;
3122         if ((my_type_of (c1) & my_type_of (c2)) == 0)
3123             break;
3124     }
3125     edit->mark2 = MIN (pos + 1, edit->buffer.size);
3126 
3127     edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
3128 }
3129 
3130 /* --------------------------------------------------------------------------------------------- */
3131 
3132 void
3133 edit_mark_current_line_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3134 {
3135     edit->mark1 = edit_buffer_get_current_bol (&edit->buffer);
3136     edit->mark2 = edit_buffer_get_current_eol (&edit->buffer);
3137 
3138     edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
3139 }
3140 
3141 /* --------------------------------------------------------------------------------------------- */
3142 
3143 void
3144 edit_delete_line (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3145 {
3146     /*
3147      * Delete right part of the line.
3148      * Note that edit_buffer_get_byte() returns '\n' when byte position is
3149      *   beyond EOF.
3150      */
3151     while (edit_buffer_get_current_byte (&edit->buffer) != '\n')
3152         (void) edit_delete (edit, TRUE);
3153 
3154     /*
3155      * Delete '\n' char.
3156      * Note that edit_delete() will not corrupt anything if called while
3157      *   cursor position is EOF.
3158      */
3159     (void) edit_delete (edit, TRUE);
3160 
3161     /*
3162      * Delete left part of the line.
3163      * Note, that edit_buffer_get_byte() returns '\n' when byte position is < 0.
3164      */
3165     while (edit_buffer_get_previous_byte (&edit->buffer) != '\n')
3166         (void) edit_backspace (edit, TRUE);
3167 }
3168 
3169 /* --------------------------------------------------------------------------------------------- */
3170 
3171 void
3172 edit_push_key_press (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3173 {
3174     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
3175     if (edit->mark2 == -1)
3176     {
3177         edit_push_undo_action (edit, MARK_1 + edit->mark1);
3178         edit_push_undo_action (edit, MARK_CURS + edit->end_mark_curs);
3179     }
3180 }
3181 
3182 /* --------------------------------------------------------------------------------------------- */
3183 
3184 void
3185 edit_find_bracket (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
3186 {
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;
3191 }
3192 
3193 /* --------------------------------------------------------------------------------------------- */
3194 /**
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.
3202  */
3203 
3204 void
3205 edit_execute_key_command (WEdit * edit, long command, int char_for_insertion)
     /* [previous][next][first][last][top][bottom][index][help]  */
3206 {
3207     if (command == CK_MacroStartRecord || command == CK_RepeatStartRecord
3208         || (macro_index < 0
3209             && (command == CK_MacroStartStopRecord || command == CK_RepeatStartStopRecord)))
3210     {
3211         macro_index = 0;
3212         edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
3213         return;
3214     }
3215     if (macro_index != -1)
3216     {
3217         edit->force |= REDRAW_COMPLETELY;
3218         if (command == CK_MacroStopRecord || command == CK_MacroStartStopRecord)
3219         {
3220             edit_store_macro_cmd (edit);
3221             macro_index = -1;
3222             return;
3223         }
3224         if (command == CK_RepeatStopRecord || command == CK_RepeatStartStopRecord)
3225         {
3226             edit_repeat_macro_cmd (edit);
3227             macro_index = -1;
3228             return;
3229         }
3230     }
3231 
3232     if (macro_index >= 0 && macro_index < MAX_MACRO_LENGTH - 1)
3233     {
3234         record_macro_buf[macro_index].action = command;
3235         record_macro_buf[macro_index++].ch = char_for_insertion;
3236     }
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);
3240 
3241     edit_execute_cmd (edit, command, char_for_insertion);
3242     if (edit->column_highlight)
3243         edit->force |= REDRAW_PAGE;
3244 }
3245 
3246 /* --------------------------------------------------------------------------------------------- */
3247 /**
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.
3252  */
3253 void
3254 edit_execute_cmd (WEdit * edit, long command, int char_for_insertion)
     /* [previous][next][first][last][top][bottom][index][help]  */
3255 {
3256     WRect *w = &WIDGET (edit)->rect;
3257 
3258     if (command == CK_WindowFullscreen)
3259     {
3260         edit_toggle_fullscreen (edit);
3261         return;
3262     }
3263 
3264     /* handle window state */
3265     if (edit_handle_move_resize (edit, command))
3266         return;
3267 
3268     edit->force |= REDRAW_LINE;
3269 
3270     /* The next key press will unhighlight the found string, so update
3271      * the whole page */
3272     if (edit->found_len || edit->column_highlight)
3273         edit->force |= REDRAW_PAGE;
3274 
3275     switch (command)
3276     {
3277         /* a mark command with shift-arrow */
3278     case CK_MarkLeft:
3279     case CK_MarkRight:
3280     case CK_MarkToWordBegin:
3281     case CK_MarkToWordEnd:
3282     case CK_MarkToHome:
3283     case CK_MarkToEnd:
3284     case CK_MarkUp:
3285     case CK_MarkDown:
3286     case CK_MarkPageUp:
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))
3309         {
3310             edit_mark_cmd (edit, TRUE); /* clear */
3311             edit_mark_cmd (edit, FALSE);        /* marking on */
3312         }
3313         edit->highlight = 1;
3314         break;
3315 
3316         /* any other command */
3317     default:
3318         if (edit->highlight)
3319             edit_mark_cmd (edit, FALSE);        /* clear */
3320         edit->highlight = 0;
3321     }
3322 
3323     /* first check for undo */
3324     if (command == CK_Undo)
3325     {
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;
3331         return;
3332     }
3333     /*  check for redo */
3334     if (command == CK_Redo)
3335     {
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;
3341         return;
3342     }
3343 
3344     edit->redo_stack_reset = 1;
3345 
3346     /* An ordinary key press */
3347     if (char_for_insertion >= 0)
3348     {
3349         /* if non persistent selection and text selected */
3350         if (!option_persistent_selections && edit->mark1 != edit->mark2)
3351             edit_block_delete_cmd (edit);
3352 
3353         if (edit->overwrite)
3354         {
3355             /* remove char only one time, after input first byte, multibyte chars */
3356 #ifdef HAVE_CHARSET
3357             if (!mc_global.utf8_display || edit->charpoint == 0)
3358 #endif
3359                 if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
3360 
3361                     edit_delete (edit, FALSE);
3362         }
3363         if (option_cursor_beyond_eol && edit->over_col > 0)
3364             edit_insert_over (edit);
3365 #ifdef HAVE_CHARSET
3366         /**
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.
3369         */
3370         if (char_for_insertion > 127 && str_isutf8 (get_codepage_id (mc_global.source_codepage))
3371             && !mc_global.utf8_display)
3372         {
3373             unsigned char str[UTF8_CHAR_LEN + 1];
3374             size_t i = 0;
3375             int res;
3376 
3377             res = g_unichar_to_utf8 (char_for_insertion, (char *) str);
3378             if (res == 0)
3379             {
3380                 str[0] = '.';
3381                 str[1] = '\0';
3382             }
3383             else
3384             {
3385                 str[res] = '\0';
3386             }
3387             while (i <= UTF8_CHAR_LEN && str[i] != '\0')
3388             {
3389                 char_for_insertion = str[i];
3390                 edit_insert (edit, char_for_insertion);
3391                 i++;
3392             }
3393         }
3394         else
3395 #endif
3396             edit_insert (edit, char_for_insertion);
3397 
3398         if (option_auto_para_formatting)
3399         {
3400             format_paragraph (edit, FALSE);
3401             edit->force |= REDRAW_PAGE;
3402         }
3403         else
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);
3409         return;
3410     }
3411 
3412     switch (command)
3413     {
3414     case CK_TopOnScreen:
3415     case CK_BottomOnScreen:
3416     case CK_Top:
3417     case CK_Bottom:
3418     case CK_PageUp:
3419     case CK_PageDown:
3420     case CK_Home:
3421     case CK_End:
3422     case CK_Up:
3423     case CK_Down:
3424     case CK_Left:
3425     case CK_Right:
3426     case CK_WordLeft:
3427     case CK_WordRight:
3428         if (!option_persistent_selections && edit->mark2 >= 0)
3429         {
3430             if (edit->column_highlight)
3431                 edit_push_undo_action (edit, COLUMN_ON);
3432             edit->column_highlight = 0;
3433             edit_mark_cmd (edit, TRUE);
3434         }
3435         break;
3436     default:
3437         break;
3438     }
3439 
3440     switch (command)
3441     {
3442     case CK_TopOnScreen:
3443     case CK_BottomOnScreen:
3444     case CK_MarkToPageBegin:
3445     case CK_MarkToPageEnd:
3446     case CK_Up:
3447     case CK_Down:
3448     case CK_WordLeft:
3449     case CK_WordRight:
3450     case CK_MarkToWordBegin:
3451     case CK_MarkToWordEnd:
3452     case CK_MarkUp:
3453     case CK_MarkDown:
3454     case CK_MarkColumnUp:
3455     case CK_MarkColumnDown:
3456         if (edit->mark2 == -1)
3457             break;              /*marking is following the cursor: may need to highlight a whole line */
3458         MC_FALLTHROUGH;
3459     case CK_Left:
3460     case CK_Right:
3461     case CK_MarkLeft:
3462     case CK_MarkRight:
3463         edit->force |= REDRAW_CHAR_ONLY;
3464         break;
3465     default:
3466         break;
3467     }
3468 
3469     /* basic cursor key commands */
3470     switch (command)
3471     {
3472     case CK_BackSpace:
3473         /* if non persistent selection and text selected */
3474         if (!option_persistent_selections && edit->mark1 != edit->mark2)
3475             edit_block_delete_cmd (edit);
3476         else if (option_cursor_beyond_eol && edit->over_col > 0)
3477             edit->over_col--;
3478         else if (option_backspace_through_tabs && is_in_indent (&edit->buffer))
3479         {
3480             while (edit_buffer_get_previous_byte (&edit->buffer) != '\n' && edit->buffer.curs1 > 0)
3481                 edit_backspace (edit, TRUE);
3482         }
3483         else if (option_fake_half_tabs && is_in_indent (&edit->buffer)
3484                  && right_of_four_spaces (edit))
3485         {
3486             int i;
3487 
3488             for (i = 0; i < HALF_TAB_SIZE; i++)
3489                 edit_backspace (edit, TRUE);
3490         }
3491         else
3492             edit_backspace (edit, FALSE);
3493         break;
3494     case CK_Delete:
3495         /* if non persistent selection and text selected */
3496         if (!option_persistent_selections && edit->mark1 != edit->mark2)
3497             edit_block_delete_cmd (edit);
3498         else
3499         {
3500             if (option_cursor_beyond_eol && edit->over_col > 0)
3501                 edit_insert_over (edit);
3502 
3503             if (option_fake_half_tabs && is_in_indent (&edit->buffer) && left_of_four_spaces (edit))
3504             {
3505                 int i;
3506 
3507                 for (i = 1; i <= HALF_TAB_SIZE; i++)
3508                     edit_delete (edit, TRUE);
3509             }
3510             else
3511                 edit_delete (edit, FALSE);
3512         }
3513         break;
3514     case CK_DeleteToWordBegin:
3515         edit->over_col = 0;
3516         edit_left_delete_word (edit);
3517         break;
3518     case CK_DeleteToWordEnd:
3519         if (option_cursor_beyond_eol && edit->over_col > 0)
3520             edit_insert_over (edit);
3521 
3522         edit_right_delete_word (edit);
3523         break;
3524     case CK_DeleteLine:
3525         edit_delete_line (edit);
3526         break;
3527     case CK_DeleteToHome:
3528         edit_delete_to_line_begin (edit);
3529         break;
3530     case CK_DeleteToEnd:
3531         edit_delete_to_line_end (edit);
3532         break;
3533     case CK_Enter:
3534         edit->over_col = 0;
3535         if (option_auto_para_formatting)
3536         {
3537             edit_double_newline (edit);
3538             if (option_return_does_auto_indent && !bracketed_pasting_in_progress)
3539                 edit_auto_indent (edit);
3540             format_paragraph (edit, FALSE);
3541         }
3542         else
3543         {
3544             edit_insert (edit, '\n');
3545             if (option_return_does_auto_indent && !bracketed_pasting_in_progress)
3546                 edit_auto_indent (edit);
3547         }
3548         break;
3549     case CK_Return:
3550         edit_insert (edit, '\n');
3551         break;
3552 
3553     case CK_MarkColumnPageUp:
3554         edit->column_highlight = 1;
3555         MC_FALLTHROUGH;
3556     case CK_PageUp:
3557     case CK_MarkPageUp:
3558         edit_move_up (edit, w->lines - 1, TRUE);
3559         break;
3560     case CK_MarkColumnPageDown:
3561         edit->column_highlight = 1;
3562         MC_FALLTHROUGH;
3563     case CK_PageDown:
3564     case CK_MarkPageDown:
3565         edit_move_down (edit, w->lines - 1, TRUE);
3566         break;
3567     case CK_MarkColumnLeft:
3568         edit->column_highlight = 1;
3569         MC_FALLTHROUGH;
3570     case CK_Left:
3571     case CK_MarkLeft:
3572         if (option_fake_half_tabs && is_in_indent (&edit->buffer) && right_of_four_spaces (edit))
3573         {
3574             if (option_cursor_beyond_eol && edit->over_col > 0)
3575                 edit->over_col--;
3576             else
3577                 edit_cursor_move (edit, -HALF_TAB_SIZE);
3578             edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
3579         }
3580         else
3581             edit_left_char_move_cmd (edit);
3582         break;
3583     case CK_MarkColumnRight:
3584         edit->column_highlight = 1;
3585         MC_FALLTHROUGH;
3586     case CK_Right:
3587     case CK_MarkRight:
3588         if (option_fake_half_tabs && is_in_indent (&edit->buffer) && left_of_four_spaces (edit))
3589         {
3590             edit_cursor_move (edit, HALF_TAB_SIZE);
3591             edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
3592         }
3593         else
3594             edit_right_char_move_cmd (edit);
3595         break;
3596     case CK_TopOnScreen:
3597     case CK_MarkToPageBegin:
3598         edit_begin_page (edit);
3599         break;
3600     case CK_BottomOnScreen:
3601     case CK_MarkToPageEnd:
3602         edit_end_page (edit);
3603         break;
3604     case CK_WordLeft:
3605     case CK_MarkToWordBegin:
3606         edit->over_col = 0;
3607         edit_left_word_move_cmd (edit);
3608         break;
3609     case CK_WordRight:
3610     case CK_MarkToWordEnd:
3611         edit->over_col = 0;
3612         edit_right_word_move_cmd (edit);
3613         break;
3614     case CK_MarkColumnUp:
3615         edit->column_highlight = 1;
3616         MC_FALLTHROUGH;
3617     case CK_Up:
3618     case CK_MarkUp:
3619         edit_move_up (edit, 1, FALSE);
3620         break;
3621     case CK_MarkColumnDown:
3622         edit->column_highlight = 1;
3623         MC_FALLTHROUGH;
3624     case CK_Down:
3625     case CK_MarkDown:
3626         edit_move_down (edit, 1, FALSE);
3627         break;
3628     case CK_MarkColumnParagraphUp:
3629         edit->column_highlight = 1;
3630         MC_FALLTHROUGH;
3631     case CK_ParagraphUp:
3632     case CK_MarkParagraphUp:
3633         edit_move_up_paragraph (edit, FALSE);
3634         break;
3635     case CK_MarkColumnParagraphDown:
3636         edit->column_highlight = 1;
3637         MC_FALLTHROUGH;
3638     case CK_ParagraphDown:
3639     case CK_MarkParagraphDown:
3640         edit_move_down_paragraph (edit, FALSE);
3641         break;
3642     case CK_MarkColumnScrollUp:
3643         edit->column_highlight = 1;
3644         MC_FALLTHROUGH;
3645     case CK_ScrollUp:
3646     case CK_MarkScrollUp:
3647         edit_move_up (edit, 1, TRUE);
3648         break;
3649     case CK_MarkColumnScrollDown:
3650         edit->column_highlight = 1;
3651         MC_FALLTHROUGH;
3652     case CK_ScrollDown:
3653     case CK_MarkScrollDown:
3654         edit_move_down (edit, 1, TRUE);
3655         break;
3656     case CK_Home:
3657     case CK_MarkToHome:
3658         edit_cursor_to_bol (edit);
3659         break;
3660     case CK_End:
3661     case CK_MarkToEnd:
3662         edit_cursor_to_eol (edit);
3663         break;
3664     case CK_Tab:
3665         /* if text marked shift block */
3666         if (edit->mark1 != edit->mark2 && !option_persistent_selections)
3667         {
3668             if (edit->mark2 < 0)
3669                 edit_mark_cmd (edit, FALSE);
3670             edit_move_block_to_right (edit);
3671         }
3672         else
3673         {
3674             if (option_cursor_beyond_eol)
3675                 edit_insert_over (edit);
3676             edit_tab_cmd (edit);
3677             if (option_auto_para_formatting)
3678             {
3679                 format_paragraph (edit, FALSE);
3680                 edit->force |= REDRAW_PAGE;
3681             }
3682             else
3683                 check_and_wrap_line (edit);
3684         }
3685         break;
3686 
3687     case CK_InsertOverwrite:
3688         edit->overwrite = !edit->overwrite;
3689         break;
3690 
3691     case CK_Mark:
3692         if (edit->mark2 >= 0)
3693         {
3694             if (edit->column_highlight)
3695                 edit_push_undo_action (edit, COLUMN_ON);
3696             edit->column_highlight = 0;
3697         }
3698         edit_mark_cmd (edit, FALSE);
3699         break;
3700     case CK_MarkColumn:
3701         if (!edit->column_highlight)
3702             edit_push_undo_action (edit, COLUMN_OFF);
3703         edit->column_highlight = 1;
3704         edit_mark_cmd (edit, FALSE);
3705         break;
3706     case CK_MarkAll:
3707         edit_set_markers (edit, 0, edit->buffer.size, 0, 0);
3708         edit->force |= REDRAW_PAGE;
3709         break;
3710     case CK_Unmark:
3711         if (edit->column_highlight)
3712             edit_push_undo_action (edit, COLUMN_ON);
3713         edit->column_highlight = 0;
3714         edit_mark_cmd (edit, TRUE);
3715         break;
3716     case CK_MarkWord:
3717         if (edit->column_highlight)
3718             edit_push_undo_action (edit, COLUMN_ON);
3719         edit->column_highlight = 0;
3720         edit_mark_current_word_cmd (edit);
3721         break;
3722     case CK_MarkLine:
3723         if (edit->column_highlight)
3724             edit_push_undo_action (edit, COLUMN_ON);
3725         edit->column_highlight = 0;
3726         edit_mark_current_line_cmd (edit);
3727         break;
3728 
3729     case CK_Bookmark:
3730         book_mark_clear (edit, edit->buffer.curs_line, BOOK_MARK_FOUND_COLOR);
3731         if (book_mark_query_color (edit, edit->buffer.curs_line, BOOK_MARK_COLOR))
3732             book_mark_clear (edit, edit->buffer.curs_line, BOOK_MARK_COLOR);
3733         else
3734             book_mark_insert (edit, edit->buffer.curs_line, BOOK_MARK_COLOR);
3735         break;
3736     case CK_BookmarkFlush:
3737         book_mark_flush (edit, BOOK_MARK_COLOR);
3738         book_mark_flush (edit, BOOK_MARK_FOUND_COLOR);
3739         edit->force |= REDRAW_PAGE;
3740         break;
3741     case CK_BookmarkNext:
3742         if (edit->book_mark != NULL)
3743         {
3744             edit_book_mark_t *p;
3745 
3746             p = book_mark_find (edit, edit->buffer.curs_line);
3747             if (p->next != NULL)
3748             {
3749                 p = p->next;
3750                 if (p->line >= edit->start_line + w->lines || p->line < edit->start_line)
3751                     edit_move_display (edit, p->line - w->lines / 2);
3752                 edit_move_to_line (edit, p->line);
3753             }
3754         }
3755         break;
3756     case CK_BookmarkPrev:
3757         if (edit->book_mark != NULL)
3758         {
3759             edit_book_mark_t *p;
3760 
3761             p = book_mark_find (edit, edit->buffer.curs_line);
3762             while (p->line == edit->buffer.curs_line)
3763                 if (p->prev != NULL)
3764                     p = p->prev;
3765             if (p->line >= 0)
3766             {
3767                 if (p->line >= edit->start_line + w->lines || p->line < edit->start_line)
3768                     edit_move_display (edit, p->line - w->lines / 2);
3769                 edit_move_to_line (edit, p->line);
3770             }
3771         }
3772         break;
3773 
3774     case CK_Top:
3775     case CK_MarkToFileBegin:
3776         edit_move_to_top (edit);
3777         break;
3778     case CK_Bottom:
3779     case CK_MarkToFileEnd:
3780         edit_move_to_bottom (edit);
3781         break;
3782 
3783     case CK_Copy:
3784         if (option_cursor_beyond_eol && edit->over_col > 0)
3785             edit_insert_over (edit);
3786         edit_block_copy_cmd (edit);
3787         break;
3788     case CK_Remove:
3789         edit_block_delete_cmd (edit);
3790         break;
3791     case CK_Move:
3792         edit_block_move_cmd (edit);
3793         break;
3794 
3795     case CK_BlockShiftLeft:
3796         if (edit->mark1 != edit->mark2)
3797             edit_move_block_to_left (edit);
3798         break;
3799     case CK_BlockShiftRight:
3800         if (edit->mark1 != edit->mark2)
3801             edit_move_block_to_right (edit);
3802         break;
3803     case CK_Store:
3804         edit_copy_to_X_buf_cmd (edit);
3805         break;
3806     case CK_Cut:
3807         edit_cut_to_X_buf_cmd (edit);
3808         break;
3809     case CK_Paste:
3810         /* if non persistent selection and text selected */
3811         if (!option_persistent_selections && edit->mark1 != edit->mark2)
3812             edit_block_delete_cmd (edit);
3813         if (option_cursor_beyond_eol && edit->over_col > 0)
3814             edit_insert_over (edit);
3815         edit_paste_from_X_buf_cmd (edit);
3816         if (!option_persistent_selections && edit->mark2 >= 0)
3817         {
3818             if (edit->column_highlight)
3819                 edit_push_undo_action (edit, COLUMN_ON);
3820             edit->column_highlight = 0;
3821             edit_mark_cmd (edit, TRUE);
3822         }
3823         break;
3824     case CK_History:
3825         edit_paste_from_history (edit);
3826         break;
3827 
3828     case CK_SaveAs:
3829         edit_save_as_cmd (edit);
3830         break;
3831     case CK_Save:
3832         edit_save_confirm_cmd (edit);
3833         break;
3834     case CK_BlockSave:
3835         edit_save_block_cmd (edit);
3836         break;
3837     case CK_InsertFile:
3838         edit_insert_file_cmd (edit);
3839         break;
3840 
3841     case CK_FilePrev:
3842         edit_load_back_cmd (edit);
3843         break;
3844     case CK_FileNext:
3845         edit_load_forward_cmd (edit);
3846         break;
3847 
3848     case CK_SyntaxChoose:
3849         edit_syntax_dialog (edit);
3850         break;
3851 
3852     case CK_Search:
3853         edit_search_cmd (edit, FALSE);
3854         break;
3855     case CK_SearchContinue:
3856         edit_search_cmd (edit, TRUE);
3857         break;
3858     case CK_Replace:
3859         edit_replace_cmd (edit, FALSE);
3860         break;
3861     case CK_ReplaceContinue:
3862         edit_replace_cmd (edit, TRUE);
3863         break;
3864     case CK_Complete:
3865         /* if text marked shift block */
3866         if (edit->mark1 != edit->mark2 && !option_persistent_selections)
3867             edit_move_block_to_left (edit);
3868         else
3869             edit_complete_word_cmd (edit);
3870         break;
3871     case CK_Find:
3872         edit_get_match_keyword_cmd (edit);
3873         break;
3874 
3875 #ifdef HAVE_ASPELL
3876     case CK_SpellCheckCurrentWord:
3877         edit_suggest_current_word (edit);
3878         break;
3879     case CK_SpellCheck:
3880         edit_spellcheck_file (edit);
3881         break;
3882     case CK_SpellCheckSelectLang:
3883         edit_set_spell_lang ();
3884         break;
3885 #endif
3886 
3887     case CK_Date:
3888         {
3889             char s[BUF_MEDIUM];
3890             /* fool gcc to prevent a Y2K warning */
3891             char time_format[] = "_c";
3892             time_format[0] = '%';
3893 
3894             FMT_LOCALTIME_CURRENT (s, sizeof (s), time_format);
3895             edit_print_string (edit, s);
3896             edit->force |= REDRAW_PAGE;
3897         }
3898         break;
3899     case CK_Goto:
3900         edit_goto_cmd (edit);
3901         break;
3902     case CK_ParagraphFormat:
3903         format_paragraph (edit, TRUE);
3904         edit->force |= REDRAW_PAGE;
3905         break;
3906     case CK_MacroDelete:
3907         edit_delete_macro_cmd (edit);
3908         break;
3909     case CK_MatchBracket:
3910         edit_goto_matching_bracket (edit);
3911         break;
3912     case CK_UserMenu:
3913         user_menu (edit, NULL, -1);
3914         break;
3915     case CK_Sort:
3916         edit_sort_cmd (edit);
3917         break;
3918     case CK_ExternalCommand:
3919         edit_ext_cmd (edit);
3920         break;
3921     case CK_EditMail:
3922         edit_mail_dialog (edit);
3923         break;
3924 #ifdef HAVE_CHARSET
3925     case CK_SelectCodepage:
3926         edit_select_codepage_cmd (edit);
3927         break;
3928 #endif
3929     case CK_InsertLiteral:
3930         edit_insert_literal_cmd (edit);
3931         break;
3932     case CK_MacroStartStopRecord:
3933         edit_begin_end_macro_cmd (edit);
3934         break;
3935     case CK_RepeatStartStopRecord:
3936         edit_begin_end_repeat_cmd (edit);
3937         break;
3938     case CK_ExtendedKeyMap:
3939         WIDGET (edit)->ext_mode = TRUE;
3940         break;
3941     default:
3942         break;
3943     }
3944 
3945     /* CK_PipeBlock */
3946     if ((command / CK_PipeBlock (0)) == 1)
3947         edit_block_process_cmd (edit, command - CK_PipeBlock (0));
3948 
3949     /* keys which must set the col position, and the search vars */
3950     switch (command)
3951     {
3952     case CK_Search:
3953     case CK_SearchContinue:
3954     case CK_Replace:
3955     case CK_ReplaceContinue:
3956     case CK_Complete:
3957         edit->prev_col = edit_get_col (edit);
3958         break;
3959     case CK_Up:
3960     case CK_MarkUp:
3961     case CK_MarkColumnUp:
3962     case CK_Down:
3963     case CK_MarkDown:
3964     case CK_MarkColumnDown:
3965     case CK_PageUp:
3966     case CK_MarkPageUp:
3967     case CK_MarkColumnPageUp:
3968     case CK_PageDown:
3969     case CK_MarkPageDown:
3970     case CK_MarkColumnPageDown:
3971     case CK_Top:
3972     case CK_MarkToFileBegin:
3973     case CK_Bottom:
3974     case CK_MarkToFileEnd:
3975     case CK_ParagraphUp:
3976     case CK_MarkParagraphUp:
3977     case CK_MarkColumnParagraphUp:
3978     case CK_ParagraphDown:
3979     case CK_MarkParagraphDown:
3980     case CK_MarkColumnParagraphDown:
3981     case CK_ScrollUp:
3982     case CK_MarkScrollUp:
3983     case CK_MarkColumnScrollUp:
3984     case CK_ScrollDown:
3985     case CK_MarkScrollDown:
3986     case CK_MarkColumnScrollDown:
3987         edit->search_start = edit->buffer.curs1;
3988         edit->found_len = 0;
3989         break;
3990     default:
3991         edit->found_len = 0;
3992         edit->prev_col = edit_get_col (edit);
3993         edit->search_start = edit->buffer.curs1;
3994     }
3995     edit_find_bracket (edit);
3996 
3997     if (option_auto_para_formatting)
3998     {
3999         switch (command)
4000         {
4001         case CK_BackSpace:
4002         case CK_Delete:
4003         case CK_DeleteToWordBegin:
4004         case CK_DeleteToWordEnd:
4005         case CK_DeleteToHome:
4006         case CK_DeleteToEnd:
4007             format_paragraph (edit, FALSE);
4008             edit->force |= REDRAW_PAGE;
4009             break;
4010         default:
4011             break;
4012         }
4013     }
4014 }
4015 
4016 /* --------------------------------------------------------------------------------------------- */
4017 
4018 void
4019 edit_stack_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
4020 {
4021     for (edit_stack_iterator = 0; edit_stack_iterator < MAX_HISTORY_MOVETO; edit_stack_iterator++)
4022     {
4023         edit_history_moveto[edit_stack_iterator].filename_vpath = NULL;
4024         edit_history_moveto[edit_stack_iterator].line = -1;
4025     }
4026 
4027     edit_stack_iterator = 0;
4028 }
4029 
4030 /* --------------------------------------------------------------------------------------------- */
4031 
4032 void
4033 edit_stack_free (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
4034 {
4035     for (edit_stack_iterator = 0; edit_stack_iterator < MAX_HISTORY_MOVETO; edit_stack_iterator++)
4036         vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath, TRUE);
4037 }
4038 
4039 /* --------------------------------------------------------------------------------------------- */
4040 /** move i lines */
4041 
4042 void
4043 edit_move_up (WEdit * edit, long i, gboolean do_scroll)
     /* [previous][next][first][last][top][bottom][index][help]  */
4044 {
4045     edit_move_updown (edit, i, do_scroll, TRUE);
4046 }
4047 
4048 /* --------------------------------------------------------------------------------------------- */
4049 /** move i lines */
4050 
4051 void
4052 edit_move_down (WEdit * edit, long i, gboolean do_scroll)
     /* [previous][next][first][last][top][bottom][index][help]  */
4053 {
4054     edit_move_updown (edit, i, do_scroll, FALSE);
4055 }
4056 
4057 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */